this is avaiable project

Dependents:   LoRaWAN_MBED

Fork of LoRaMacLib by LoRa All

Committer:
Alliance
Date:
Fri Nov 06 17:38:56 2015 +0000
Revision:
8:19a3b4a82c69
Parent:
5:50aab2960e8c
Child:
9:b3ddbad8c5e3
++++___+

Who changed what in which revision?

UserRevisionLine numberNew contents of line
GregCr 0:9be122c18509 1 /*
GregCr 0:9be122c18509 2 / _____) _ | |
GregCr 0:9be122c18509 3 ( (____ _____ ____ _| |_ _____ ____| |__
GregCr 0:9be122c18509 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
GregCr 0:9be122c18509 5 _____) ) ____| | | || |_| ____( (___| | | |
GregCr 0:9be122c18509 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
GregCr 0:9be122c18509 7 (C)2013 Semtech
GregCr 0:9be122c18509 8
GregCr 0:9be122c18509 9 Description: LoRa MAC layer implementation
GregCr 0:9be122c18509 10
GregCr 0:9be122c18509 11 License: Revised BSD License, see LICENSE.TXT file include in the project
GregCr 0:9be122c18509 12
GregCr 0:9be122c18509 13 Maintainer: Miguel Luis and Gregory Cristian
GregCr 0:9be122c18509 14 */
GregCr 0:9be122c18509 15 #include "mbed.h"
GregCr 0:9be122c18509 16 #include "board.h"
GregCr 0:9be122c18509 17 #include "utilities.h"
GregCr 0:9be122c18509 18 #include "sx1276-hal.h"
GregCr 0:9be122c18509 19 #include "LoRaMac.h"
GregCr 0:9be122c18509 20 #include "LoRaMacCrypto.h"
GregCr 0:9be122c18509 21
GregCr 0:9be122c18509 22 /*!
GregCr 0:9be122c18509 23 * Maximum PHY layer payload size
GregCr 0:9be122c18509 24 */
GregCr 0:9be122c18509 25 #define LORAMAC_PHY_MAXPAYLOAD 64
GregCr 0:9be122c18509 26
GregCr 0:9be122c18509 27 /*!
GregCr 0:9be122c18509 28 * Device IEEE EUI
GregCr 0:9be122c18509 29 */
GregCr 0:9be122c18509 30 static uint8_t *LoRaMacDevEui;
GregCr 0:9be122c18509 31
GregCr 0:9be122c18509 32 /*!
GregCr 0:9be122c18509 33 * Application IEEE EUI
GregCr 0:9be122c18509 34 */
GregCr 0:9be122c18509 35 static uint8_t *LoRaMacAppEui;
GregCr 0:9be122c18509 36
GregCr 0:9be122c18509 37 /*!
GregCr 0:9be122c18509 38 * AES encryption/decryption cipher application key
GregCr 0:9be122c18509 39 */
GregCr 0:9be122c18509 40 static uint8_t *LoRaMacAppKey;
GregCr 0:9be122c18509 41
GregCr 0:9be122c18509 42 /*!
GregCr 0:9be122c18509 43 * AES encryption/decryption cipher network session key
GregCr 0:9be122c18509 44 */
GregCr 0:9be122c18509 45 static uint8_t LoRaMacNwkSKey[] =
GregCr 0:9be122c18509 46 {
GregCr 0:9be122c18509 47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
GregCr 0:9be122c18509 48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
GregCr 0:9be122c18509 49 };
GregCr 0:9be122c18509 50
GregCr 0:9be122c18509 51 /*!
GregCr 0:9be122c18509 52 * AES encryption/decryption cipher application session key
GregCr 0:9be122c18509 53 */
GregCr 0:9be122c18509 54 static uint8_t LoRaMacAppSKey[] =
GregCr 0:9be122c18509 55 {
GregCr 0:9be122c18509 56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
GregCr 0:9be122c18509 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
GregCr 0:9be122c18509 58 };
GregCr 0:9be122c18509 59
GregCr 0:9be122c18509 60 /*!
GregCr 0:9be122c18509 61 * Device nonce is a random value extracted by issuing a sequence of RSSI
GregCr 0:9be122c18509 62 * measurements
GregCr 0:9be122c18509 63 */
GregCr 0:9be122c18509 64 static uint16_t LoRaMacDevNonce;
GregCr 0:9be122c18509 65
GregCr 0:9be122c18509 66 /*!
GregCr 0:9be122c18509 67 * Network ID ( 3 bytes )
GregCr 0:9be122c18509 68 */
GregCr 0:9be122c18509 69 static uint32_t LoRaMacNetID;
GregCr 0:9be122c18509 70
GregCr 0:9be122c18509 71 /*!
GregCr 0:9be122c18509 72 * Mote Address
GregCr 0:9be122c18509 73 */
GregCr 0:9be122c18509 74 static uint32_t LoRaMacDevAddr;
GregCr 0:9be122c18509 75
GregCr 0:9be122c18509 76 /*!
GregCr 0:9be122c18509 77 * Mutlicast channels linked list
GregCr 0:9be122c18509 78 */
GregCr 0:9be122c18509 79 static MulticastParams_t *MulticastChannels = NULL;
GregCr 0:9be122c18509 80
GregCr 0:9be122c18509 81 /*!
GregCr 0:9be122c18509 82 * Actual device class
GregCr 0:9be122c18509 83 */
GregCr 0:9be122c18509 84 static DeviceClass_t LoRaMacDeviceClass;
GregCr 0:9be122c18509 85
GregCr 0:9be122c18509 86 /*!
GregCr 0:9be122c18509 87 * Indicates if the node is connected to a private or public network
GregCr 0:9be122c18509 88 */
GregCr 0:9be122c18509 89 static bool PublicNetwork;
GregCr 0:9be122c18509 90
GregCr 0:9be122c18509 91 /*!
GregCr 0:9be122c18509 92 * Buffer containing the data to be sent or received.
GregCr 0:9be122c18509 93 */
GregCr 0:9be122c18509 94 static uint8_t LoRaMacBuffer[LORAMAC_PHY_MAXPAYLOAD];
GregCr 0:9be122c18509 95
GregCr 0:9be122c18509 96 /*!
GregCr 0:9be122c18509 97 * Length of packet in LoRaMacBuffer
GregCr 0:9be122c18509 98 */
GregCr 0:9be122c18509 99 static uint16_t LoRaMacBufferPktLen = 0;
GregCr 0:9be122c18509 100
GregCr 0:9be122c18509 101 /*!
GregCr 0:9be122c18509 102 * Buffer containing the upper layer data.
GregCr 0:9be122c18509 103 */
GregCr 0:9be122c18509 104 static uint8_t LoRaMacPayload[LORAMAC_PHY_MAXPAYLOAD];
GregCr 0:9be122c18509 105 static uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD];
GregCr 0:9be122c18509 106
GregCr 0:9be122c18509 107 /*!
GregCr 0:9be122c18509 108 * LoRaMAC frame counter. Each time a packet is sent the counter is incremented.
GregCr 0:9be122c18509 109 * Only the 16 LSB bits are sent
GregCr 0:9be122c18509 110 */
GregCr 0:9be122c18509 111 static uint32_t UpLinkCounter = 1;
GregCr 0:9be122c18509 112
GregCr 0:9be122c18509 113 /*!
GregCr 0:9be122c18509 114 * LoRaMAC frame counter. Each time a packet is received the counter is incremented.
GregCr 0:9be122c18509 115 * Only the 16 LSB bits are received
GregCr 0:9be122c18509 116 */
GregCr 0:9be122c18509 117 static uint32_t DownLinkCounter = 0;
GregCr 0:9be122c18509 118
GregCr 0:9be122c18509 119 /*!
GregCr 0:9be122c18509 120 * IsPacketCounterFixed enables the MIC field tests by fixing the
GregCr 0:9be122c18509 121 * UpLinkCounter value
GregCr 0:9be122c18509 122 */
GregCr 0:9be122c18509 123 static bool IsUpLinkCounterFixed = false;
GregCr 0:9be122c18509 124
GregCr 0:9be122c18509 125 /*!
GregCr 0:9be122c18509 126 * Used for test purposes. Disables the opening of the reception windows.
GregCr 0:9be122c18509 127 */
GregCr 0:9be122c18509 128 static bool IsRxWindowsEnabled = true;
GregCr 0:9be122c18509 129
GregCr 0:9be122c18509 130 /*!
GregCr 0:9be122c18509 131 * Indicates if the MAC layer has already joined a network.
GregCr 0:9be122c18509 132 */
GregCr 0:9be122c18509 133 static bool IsLoRaMacNetworkJoined = false;
GregCr 0:9be122c18509 134
GregCr 0:9be122c18509 135 /*!
GregCr 0:9be122c18509 136 * LoRaMac ADR control status
GregCr 0:9be122c18509 137 */
GregCr 0:9be122c18509 138 static bool AdrCtrlOn = false;
GregCr 0:9be122c18509 139
GregCr 0:9be122c18509 140 /*!
GregCr 0:9be122c18509 141 * Counts the number of missed ADR acknowledgements
GregCr 0:9be122c18509 142 */
GregCr 0:9be122c18509 143 static uint32_t AdrAckCounter = 0;
GregCr 0:9be122c18509 144
GregCr 0:9be122c18509 145 /*!
GregCr 0:9be122c18509 146 * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates
GregCr 0:9be122c18509 147 * if the nodes needs to manage the server acknowledgement.
GregCr 0:9be122c18509 148 */
GregCr 0:9be122c18509 149 static bool NodeAckRequested = false;
GregCr 0:9be122c18509 150
GregCr 0:9be122c18509 151 /*!
GregCr 0:9be122c18509 152 * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates
GregCr 0:9be122c18509 153 * if the ACK bit must be set for the next transmission
GregCr 0:9be122c18509 154 */
GregCr 0:9be122c18509 155 static bool SrvAckRequested = false;
GregCr 0:9be122c18509 156
GregCr 0:9be122c18509 157 /*!
GregCr 0:9be122c18509 158 * Indicates if the MAC layer wants to send MAC commands
GregCr 0:9be122c18509 159 */
GregCr 0:9be122c18509 160 static bool MacCommandsInNextTx = false;
GregCr 0:9be122c18509 161
GregCr 0:9be122c18509 162 /*!
GregCr 0:9be122c18509 163 * Contains the current MacCommandsBuffer index
GregCr 0:9be122c18509 164 */
GregCr 0:9be122c18509 165 static uint8_t MacCommandsBufferIndex = 0;
GregCr 0:9be122c18509 166
GregCr 0:9be122c18509 167 /*!
GregCr 0:9be122c18509 168 * Buffer containing the MAC layer commands
GregCr 0:9be122c18509 169 */
GregCr 0:9be122c18509 170 static uint8_t MacCommandsBuffer[15];
GregCr 0:9be122c18509 171
GregCr 0:9be122c18509 172 /*!
GregCr 0:9be122c18509 173 * Data rates table definition
GregCr 0:9be122c18509 174 */
GregCr 0:9be122c18509 175 const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
GregCr 0:9be122c18509 176
GregCr 0:9be122c18509 177 /*!
GregCr 0:9be122c18509 178 * Tx output powers table definition
GregCr 0:9be122c18509 179 */
GregCr 0:9be122c18509 180 const int8_t TxPowers[] = { 20, 14, 11, 8, 5, 2 };
GregCr 0:9be122c18509 181
GregCr 0:9be122c18509 182 #if defined( USE_BAND_868 )
GregCr 0:9be122c18509 183 /*!
GregCr 0:9be122c18509 184 * LoRaMac bands
GregCr 0:9be122c18509 185 */
GregCr 0:9be122c18509 186 static Band_t Bands[LORA_MAX_NB_BANDS] =
GregCr 0:9be122c18509 187 {
GregCr 0:9be122c18509 188 BAND0,
GregCr 0:9be122c18509 189 BAND1,
GregCr 0:9be122c18509 190 BAND2,
GregCr 0:9be122c18509 191 BAND3,
GregCr 0:9be122c18509 192 BAND4,
GregCr 0:9be122c18509 193 };
GregCr 0:9be122c18509 194
GregCr 0:9be122c18509 195 /*!
GregCr 0:9be122c18509 196 * LoRaMAC channels
GregCr 0:9be122c18509 197 */
GregCr 0:9be122c18509 198 static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] =
GregCr 0:9be122c18509 199 {
GregCr 0:9be122c18509 200 LC1,
GregCr 0:9be122c18509 201 LC2,
GregCr 0:9be122c18509 202 LC3,
GregCr 0:9be122c18509 203 LC4,
GregCr 0:9be122c18509 204 LC5,
GregCr 0:9be122c18509 205 LC6,
Alliance 8:19a3b4a82c69 206 /* LC7,
GregCr 0:9be122c18509 207 LC8,
Alliance 8:19a3b4a82c69 208 LC9,*/
GregCr 0:9be122c18509 209 };
GregCr 0:9be122c18509 210 #else
GregCr 0:9be122c18509 211 /*!
GregCr 0:9be122c18509 212 * LoRaMac bands
GregCr 0:9be122c18509 213 */
GregCr 0:9be122c18509 214 static Band_t Bands[LORA_MAX_NB_BANDS] =
GregCr 0:9be122c18509 215 {
GregCr 0:9be122c18509 216 BAND0,
GregCr 0:9be122c18509 217 };
GregCr 0:9be122c18509 218
GregCr 0:9be122c18509 219 /*!
GregCr 0:9be122c18509 220 * LoRaMAC channels
GregCr 0:9be122c18509 221 */
GregCr 0:9be122c18509 222 static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] =
GregCr 0:9be122c18509 223 {
GregCr 0:9be122c18509 224 LC1,
GregCr 0:9be122c18509 225 LC2,
GregCr 0:9be122c18509 226 LC3,
GregCr 0:9be122c18509 227 };
GregCr 0:9be122c18509 228 #endif
GregCr 0:9be122c18509 229
GregCr 0:9be122c18509 230 /*!
GregCr 0:9be122c18509 231 * LoRaMAC 2nd reception window settings
GregCr 0:9be122c18509 232 */
GregCr 0:9be122c18509 233 static Rx2ChannelParams_t Rx2Channel = RX_WND_2_CHANNEL;
GregCr 0:9be122c18509 234
GregCr 0:9be122c18509 235 /*!
GregCr 0:9be122c18509 236 * Datarate offset between uplink and downlink on first window
GregCr 0:9be122c18509 237 */
GregCr 0:9be122c18509 238 static uint8_t Rx1DrOffset = 0;
GregCr 0:9be122c18509 239
GregCr 0:9be122c18509 240 /*!
GregCr 0:9be122c18509 241 * Mask indicating which channels are enabled
GregCr 0:9be122c18509 242 */
GregCr 0:9be122c18509 243 static uint16_t ChannelsMask;
GregCr 0:9be122c18509 244
GregCr 0:9be122c18509 245 /*!
GregCr 0:9be122c18509 246 * Channels Tx output power
GregCr 0:9be122c18509 247 */
GregCr 0:9be122c18509 248 static int8_t ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
GregCr 0:9be122c18509 249
GregCr 0:9be122c18509 250 /*!
GregCr 0:9be122c18509 251 * Channels datarate
GregCr 0:9be122c18509 252 */
GregCr 0:9be122c18509 253 static int8_t ChannelsDatarate = LORAMAC_DEFAULT_DATARATE;
GregCr 0:9be122c18509 254
GregCr 0:9be122c18509 255 /*!
GregCr 0:9be122c18509 256 * Channels defualt datarate
GregCr 0:9be122c18509 257 */
GregCr 0:9be122c18509 258 static int8_t ChannelsDefaultDatarate = LORAMAC_DEFAULT_DATARATE;
GregCr 0:9be122c18509 259
GregCr 0:9be122c18509 260 /*!
GregCr 0:9be122c18509 261 * Number of uplink messages repetitions [1:15] (unconfirmed messages only)
GregCr 0:9be122c18509 262 */
GregCr 0:9be122c18509 263 static uint8_t ChannelsNbRep = 1; //
GregCr 0:9be122c18509 264
GregCr 0:9be122c18509 265 /*!
GregCr 0:9be122c18509 266 * Uplink messages repetitions counter
GregCr 0:9be122c18509 267 */
GregCr 0:9be122c18509 268 static uint8_t ChannelsNbRepCounter = 0;
GregCr 0:9be122c18509 269
GregCr 0:9be122c18509 270 /*!
GregCr 0:9be122c18509 271 * Maximum duty cycle
GregCr 0:9be122c18509 272 * \remark Possibility to shutdown the device. Everything else not implemented.
GregCr 0:9be122c18509 273 */
GregCr 0:9be122c18509 274 static uint8_t MaxDCycle = 0;
GregCr 0:9be122c18509 275
GregCr 0:9be122c18509 276 /*!
GregCr 0:9be122c18509 277 * Agregated duty cycle management
GregCr 0:9be122c18509 278 */
GregCr 0:9be122c18509 279 static uint16_t AggregatedDCycle;
GregCr 0:9be122c18509 280 static uint64_t AggregatedLastTxDoneTime;
GregCr 0:9be122c18509 281 static uint64_t AggregatedTimeOff;
GregCr 0:9be122c18509 282
GregCr 0:9be122c18509 283 /*!
GregCr 0:9be122c18509 284 * Enables/Disables duty cycle management (Test only)
GregCr 0:9be122c18509 285 */
GregCr 0:9be122c18509 286 static bool DutyCycleOn;
GregCr 0:9be122c18509 287
GregCr 0:9be122c18509 288 /*!
GregCr 0:9be122c18509 289 * Current channel index
GregCr 0:9be122c18509 290 */
GregCr 0:9be122c18509 291 static uint8_t Channel;
GregCr 0:9be122c18509 292
GregCr 0:9be122c18509 293 /*!
GregCr 0:9be122c18509 294 * LoRaMac internal states
GregCr 0:9be122c18509 295 */
GregCr 0:9be122c18509 296 enum LoRaMacState_e
GregCr 0:9be122c18509 297 {
GregCr 0:9be122c18509 298 MAC_IDLE = 0x00000000,
GregCr 0:9be122c18509 299 MAC_TX_RUNNING = 0x00000001,
GregCr 0:9be122c18509 300 MAC_RX = 0x00000002,
GregCr 0:9be122c18509 301 MAC_ACK_REQ = 0x00000004,
GregCr 0:9be122c18509 302 MAC_ACK_RETRY = 0x00000008,
GregCr 0:9be122c18509 303 MAC_CHANNEL_CHECK = 0x00000010,
GregCr 0:9be122c18509 304 };
GregCr 0:9be122c18509 305
GregCr 0:9be122c18509 306 /*!
GregCr 0:9be122c18509 307 * LoRaMac internal state
GregCr 0:9be122c18509 308 */
GregCr 0:9be122c18509 309 uint32_t LoRaMacState = MAC_IDLE;
GregCr 0:9be122c18509 310
GregCr 0:9be122c18509 311 /*!
GregCr 0:9be122c18509 312 * LoRaMac timer used to check the LoRaMacState (runs every second)
GregCr 0:9be122c18509 313 */
GregCr 0:9be122c18509 314 Ticker MacStateCheckTimer;
GregCr 0:9be122c18509 315
GregCr 0:9be122c18509 316 /*!
GregCr 0:9be122c18509 317 * LoRaMac upper layer event functions
GregCr 0:9be122c18509 318 */
GregCr 0:9be122c18509 319 static LoRaMacEvent_t *LoRaMacEvents;
GregCr 0:9be122c18509 320
GregCr 0:9be122c18509 321 /*!
GregCr 0:9be122c18509 322 * LoRaMac notification event flags
GregCr 0:9be122c18509 323 */
GregCr 0:9be122c18509 324 LoRaMacEventFlags_t LoRaMacEventFlags;
GregCr 0:9be122c18509 325
GregCr 0:9be122c18509 326 /*!
GregCr 0:9be122c18509 327 * LoRaMac notification event info
GregCr 0:9be122c18509 328 */
GregCr 0:9be122c18509 329 LoRaMacEventInfo_t LoRaMacEventInfo;
GregCr 0:9be122c18509 330
GregCr 0:9be122c18509 331 /*!
GregCr 0:9be122c18509 332 * Radio events function pointer
GregCr 0:9be122c18509 333 */
GregCr 0:9be122c18509 334 //static RadioEvents_t RadioEvents;
GregCr 0:9be122c18509 335
GregCr 0:9be122c18509 336 /*!
GregCr 0:9be122c18509 337 * LoRaMac channel check timer
GregCr 0:9be122c18509 338 */
GregCr 0:9be122c18509 339 Ticker ChannelCheckTimer;
GregCr 0:9be122c18509 340
GregCr 0:9be122c18509 341 /*!
GregCr 0:9be122c18509 342 * LoRaMac duty cycle delayed Tx timer
GregCr 0:9be122c18509 343 */
GregCr 0:9be122c18509 344 Ticker TxDelayedTimer;
GregCr 0:9be122c18509 345
GregCr 0:9be122c18509 346 /*!
GregCr 0:9be122c18509 347 * LoRaMac reception windows timers
GregCr 0:9be122c18509 348 */
GregCr 0:9be122c18509 349 Ticker RxWindowTimer1;
GregCr 0:9be122c18509 350 Ticker RxWindowTimer2;
GregCr 0:9be122c18509 351
GregCr 0:9be122c18509 352 /*!
GregCr 0:9be122c18509 353 * LoRaMac reception windows delay from end of Tx
GregCr 0:9be122c18509 354 */
GregCr 0:9be122c18509 355 static uint32_t ReceiveDelay1;
GregCr 0:9be122c18509 356 static uint32_t ReceiveDelay2;
GregCr 0:9be122c18509 357 static uint32_t JoinAcceptDelay1;
GregCr 0:9be122c18509 358 static uint32_t JoinAcceptDelay2;
GregCr 0:9be122c18509 359
GregCr 0:9be122c18509 360 /*!
GregCr 0:9be122c18509 361 * LoRaMac reception windows delay
GregCr 0:9be122c18509 362 * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
GregCr 0:9be122c18509 363 * join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
GregCr 0:9be122c18509 364 */
GregCr 0:9be122c18509 365 static uint32_t RxWindow1Delay;
GregCr 0:9be122c18509 366 static uint32_t RxWindow2Delay;
GregCr 0:9be122c18509 367
GregCr 0:9be122c18509 368 /*!
GregCr 0:9be122c18509 369 * LoRaMac maximum time a reception window stays open
GregCr 0:9be122c18509 370 */
GregCr 0:9be122c18509 371 static uint32_t MaxRxWindow;
GregCr 0:9be122c18509 372
GregCr 0:9be122c18509 373 /*!
GregCr 0:9be122c18509 374 * Acknowledge timeout timer. Used for packet retransmissions.
GregCr 0:9be122c18509 375 */
GregCr 0:9be122c18509 376 Ticker AckTimeoutTimer;
GregCr 0:9be122c18509 377
GregCr 0:9be122c18509 378 /*!
GregCr 0:9be122c18509 379 * Number of trials to get a frame acknowledged
GregCr 0:9be122c18509 380 */
GregCr 0:9be122c18509 381 static uint8_t AckTimeoutRetries = 1;
GregCr 0:9be122c18509 382
GregCr 0:9be122c18509 383 /*!
GregCr 0:9be122c18509 384 * Number of trials to get a frame acknowledged
GregCr 0:9be122c18509 385 */
GregCr 0:9be122c18509 386 static uint8_t AckTimeoutRetriesCounter = 1;
GregCr 0:9be122c18509 387
GregCr 0:9be122c18509 388 /*!
GregCr 0:9be122c18509 389 * Indicates if the AckTimeout timer has expired or not
GregCr 0:9be122c18509 390 */
GregCr 0:9be122c18509 391 static bool AckTimeoutRetry = false;
GregCr 0:9be122c18509 392
GregCr 0:9be122c18509 393 /*!
GregCr 0:9be122c18509 394 * Last transmission time on air
GregCr 0:9be122c18509 395 */
GregCr 0:9be122c18509 396 TimerTime_t TxTimeOnAir = 0;
GregCr 0:9be122c18509 397
GregCr 0:9be122c18509 398 /*!
GregCr 0:9be122c18509 399 * Function to be executed on Radio Tx Done event
GregCr 0:9be122c18509 400 */
GregCr 0:9be122c18509 401 static void OnRadioTxDone( void );
GregCr 0:9be122c18509 402
GregCr 0:9be122c18509 403 /*!
GregCr 0:9be122c18509 404 * Function to be executed on Radio Rx Done event
GregCr 0:9be122c18509 405 */
GregCr 0:9be122c18509 406 static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
GregCr 0:9be122c18509 407
GregCr 0:9be122c18509 408 /*!
GregCr 0:9be122c18509 409 * Function executed on Radio Tx Timeout event
GregCr 0:9be122c18509 410 */
GregCr 0:9be122c18509 411 static void OnRadioTxTimeout( void );
GregCr 0:9be122c18509 412
GregCr 0:9be122c18509 413 /*!
GregCr 0:9be122c18509 414 * Function executed on Radio Rx error event
GregCr 0:9be122c18509 415 */
GregCr 0:9be122c18509 416 static void OnRadioRxError( void );
GregCr 0:9be122c18509 417
GregCr 0:9be122c18509 418 /*!
GregCr 0:9be122c18509 419 * Function executed on Radio Rx Timeout event
GregCr 0:9be122c18509 420 */
GregCr 0:9be122c18509 421 static void OnRadioRxTimeout( void );
GregCr 0:9be122c18509 422
GregCr 0:9be122c18509 423 /*!
GregCr 0:9be122c18509 424 * Function executed on Resend Frame timer event.
GregCr 0:9be122c18509 425 */
GregCr 0:9be122c18509 426 static void OnMacStateCheckTimerEvent( void );
GregCr 0:9be122c18509 427
GregCr 0:9be122c18509 428 /*!
GregCr 0:9be122c18509 429 * Function executed on duty cycle delayed Tx timer event
GregCr 0:9be122c18509 430 */
GregCr 0:9be122c18509 431 static void OnTxDelayedTimerEvent( void );
GregCr 0:9be122c18509 432
GregCr 0:9be122c18509 433 /*!
GregCr 0:9be122c18509 434 * Function executed on channel check timer event
GregCr 0:9be122c18509 435 */
GregCr 0:9be122c18509 436 static void OnChannelCheckTimerEvent( void );
GregCr 0:9be122c18509 437
GregCr 0:9be122c18509 438 /*!
GregCr 0:9be122c18509 439 * Function executed on first Rx window timer event
GregCr 0:9be122c18509 440 */
GregCr 0:9be122c18509 441 static void OnRxWindow1TimerEvent( void );
GregCr 0:9be122c18509 442
GregCr 0:9be122c18509 443 /*!
GregCr 0:9be122c18509 444 * Function executed on second Rx window timer event
GregCr 0:9be122c18509 445 */
GregCr 0:9be122c18509 446 static void OnRxWindow2TimerEvent( void );
GregCr 0:9be122c18509 447
GregCr 0:9be122c18509 448 /*!
GregCr 0:9be122c18509 449 * Function executed on AckTimeout timer event
GregCr 0:9be122c18509 450 */
GregCr 0:9be122c18509 451 static void OnAckTimeoutTimerEvent( void );
GregCr 0:9be122c18509 452
GregCr 0:9be122c18509 453
GregCr 0:9be122c18509 454
GregCr 0:9be122c18509 455 SX1276MB1xAS Radio( OnRadioTxDone, OnRadioTxTimeout, OnRadioRxDone, OnRadioRxTimeout, OnRadioRxError, NULL, NULL );
GregCr 0:9be122c18509 456
GregCr 0:9be122c18509 457
GregCr 0:9be122c18509 458
GregCr 0:9be122c18509 459
GregCr 0:9be122c18509 460
GregCr 0:9be122c18509 461 /*!
GregCr 0:9be122c18509 462 * Searches and set the next random available channel
GregCr 0:9be122c18509 463 *
GregCr 0:9be122c18509 464 * \retval status Function status [0: OK, 1: Unable to find a free channel]
GregCr 0:9be122c18509 465 */
GregCr 0:9be122c18509 466 static uint8_t LoRaMacSetNextChannel( void )
GregCr 0:9be122c18509 467 {
GregCr 0:9be122c18509 468 uint8_t i = 0;
GregCr 0:9be122c18509 469 uint8_t j = 0;
GregCr 0:9be122c18509 470 uint8_t channelNext = Channel;
GregCr 0:9be122c18509 471 uint8_t nbEnabledChannels = 0;
GregCr 0:9be122c18509 472 uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
GregCr 0:9be122c18509 473 uint64_t curTime = TimerGetCurrentTime( );
GregCr 0:9be122c18509 474
GregCr 0:9be122c18509 475 memset( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
GregCr 0:9be122c18509 476
GregCr 0:9be122c18509 477 // Update Aggregated duty cycle
GregCr 0:9be122c18509 478 if( AggregatedTimeOff < ( curTime - AggregatedLastTxDoneTime ) )
GregCr 0:9be122c18509 479 {
GregCr 0:9be122c18509 480 AggregatedTimeOff = 0;
GregCr 0:9be122c18509 481 }
GregCr 0:9be122c18509 482
GregCr 0:9be122c18509 483 // Update bands Time OFF
GregCr 0:9be122c18509 484 uint64_t minTime = 0xFFFFFFFFFFFFFFFF;
GregCr 0:9be122c18509 485 for( i = 0; i < LORA_MAX_NB_BANDS; i++ )
GregCr 0:9be122c18509 486 {
GregCr 0:9be122c18509 487 if( DutyCycleOn == true )
GregCr 0:9be122c18509 488 {
GregCr 0:9be122c18509 489 if( Bands[i].TimeOff < ( curTime - Bands[i].LastTxDoneTime ) )
GregCr 0:9be122c18509 490 {
GregCr 0:9be122c18509 491 Bands[i].TimeOff = 0;
GregCr 0:9be122c18509 492 }
GregCr 0:9be122c18509 493 if( Bands[i].TimeOff != 0 )
GregCr 0:9be122c18509 494 {
GregCr 0:9be122c18509 495 minTime = MIN( Bands[i].TimeOff, minTime );
GregCr 0:9be122c18509 496 }
GregCr 0:9be122c18509 497 }
GregCr 0:9be122c18509 498 else
GregCr 0:9be122c18509 499 {
GregCr 0:9be122c18509 500 minTime = 0;
GregCr 0:9be122c18509 501 Bands[i].TimeOff = 0;
GregCr 0:9be122c18509 502 }
GregCr 0:9be122c18509 503 }
GregCr 0:9be122c18509 504
GregCr 0:9be122c18509 505 // Search how many channels are enabled
GregCr 0:9be122c18509 506 for( i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
GregCr 0:9be122c18509 507 {
GregCr 0:9be122c18509 508 if( ( ( 1 << i ) & ChannelsMask ) != 0 )
GregCr 0:9be122c18509 509 {
GregCr 0:9be122c18509 510 if( Channels[i].Frequency == 0 )
GregCr 0:9be122c18509 511 { // Check if the channel is enabled
GregCr 0:9be122c18509 512 continue;
GregCr 0:9be122c18509 513 }
GregCr 0:9be122c18509 514 if( ( ( Channels[i].DrRange.Fields.Min <= ChannelsDatarate ) &&
GregCr 0:9be122c18509 515 ( ChannelsDatarate <= Channels[i].DrRange.Fields.Max ) ) == false )
GregCr 0:9be122c18509 516 { // Check if the current channel selection supports the given datarate
GregCr 0:9be122c18509 517 continue;
GregCr 0:9be122c18509 518 }
GregCr 0:9be122c18509 519 if( Bands[Channels[i].Band].TimeOff > 0 )
GregCr 0:9be122c18509 520 { // Check if the band is available for transmission
GregCr 0:9be122c18509 521 continue;
GregCr 0:9be122c18509 522 }
GregCr 0:9be122c18509 523 if( AggregatedTimeOff > 0 )
GregCr 0:9be122c18509 524 { // Check if there is time available for transmission
GregCr 0:9be122c18509 525 continue;
GregCr 0:9be122c18509 526 }
GregCr 0:9be122c18509 527 enabledChannels[nbEnabledChannels++] = i;
GregCr 0:9be122c18509 528 }
GregCr 0:9be122c18509 529 }
GregCr 0:9be122c18509 530 if( nbEnabledChannels > 0 )
GregCr 0:9be122c18509 531 {
GregCr 0:9be122c18509 532 for( i = 0, j = randr( 0, nbEnabledChannels - 1 ); i < LORA_MAX_NB_CHANNELS; i++ )
GregCr 0:9be122c18509 533 {
GregCr 0:9be122c18509 534 channelNext = enabledChannels[j];
GregCr 0:9be122c18509 535 j = ( j + 1 ) % nbEnabledChannels;
GregCr 0:9be122c18509 536
GregCr 0:9be122c18509 537 if( Radio.IsChannelFree( MODEM_LORA, Channels[channelNext].Frequency, RSSI_FREE_TH ) == true )
GregCr 0:9be122c18509 538 {
GregCr 0:9be122c18509 539 // Free channel found
GregCr 0:9be122c18509 540 Channel = channelNext;
GregCr 0:9be122c18509 541
GregCr 0:9be122c18509 542 LoRaMacState &= ~MAC_CHANNEL_CHECK;
GregCr 0:9be122c18509 543 ChannelCheckTimer.detach( );
GregCr 0:9be122c18509 544 return 0;
GregCr 0:9be122c18509 545 }
GregCr 0:9be122c18509 546 }
GregCr 0:9be122c18509 547 }
GregCr 0:9be122c18509 548 // No free channel found.
GregCr 0:9be122c18509 549 // Check again
GregCr 0:9be122c18509 550 if( ( LoRaMacState & MAC_CHANNEL_CHECK ) == 0 )
GregCr 0:9be122c18509 551 {
GregCr 0:9be122c18509 552 ChannelCheckTimer.attach_us( OnChannelCheckTimerEvent, minTime );
GregCr 0:9be122c18509 553 LoRaMacState |= MAC_CHANNEL_CHECK;
GregCr 0:9be122c18509 554 }
GregCr 0:9be122c18509 555 return 1;
GregCr 0:9be122c18509 556 }
GregCr 0:9be122c18509 557
GregCr 0:9be122c18509 558 /*
GregCr 0:9be122c18509 559 * TODO: Add documentation
GregCr 0:9be122c18509 560 */
GregCr 0:9be122c18509 561 void OnChannelCheckTimerEvent( void )
GregCr 0:9be122c18509 562 {
GregCr 2:737ad7fbc97e 563 ChannelCheckTimer.detach( );
GregCr 0:9be122c18509 564
GregCr 0:9be122c18509 565 LoRaMacState &= ~MAC_CHANNEL_CHECK;
GregCr 0:9be122c18509 566 if( LoRaMacSetNextChannel( ) == 0 )
GregCr 0:9be122c18509 567 {
GregCr 0:9be122c18509 568 if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
GregCr 0:9be122c18509 569 {
GregCr 0:9be122c18509 570 LoRaMacSendFrameOnChannel( Channels[Channel] );
GregCr 0:9be122c18509 571 }
GregCr 0:9be122c18509 572 }
GregCr 0:9be122c18509 573 }
GregCr 0:9be122c18509 574
GregCr 0:9be122c18509 575 /*!
GregCr 0:9be122c18509 576 * Adds a new MAC command to be sent.
GregCr 0:9be122c18509 577 *
GregCr 0:9be122c18509 578 * \Remark MAC layer internal function
GregCr 0:9be122c18509 579 *
GregCr 0:9be122c18509 580 * \param [in] cmd MAC command to be added
GregCr 0:9be122c18509 581 * [MOTE_MAC_LINK_CHECK_REQ,
GregCr 0:9be122c18509 582 * MOTE_MAC_LINK_ADR_ANS,
GregCr 0:9be122c18509 583 * MOTE_MAC_DUTY_CYCLE_ANS,
GregCr 0:9be122c18509 584 * MOTE_MAC_RX2_PARAM_SET_ANS,
GregCr 0:9be122c18509 585 * MOTE_MAC_DEV_STATUS_ANS
GregCr 0:9be122c18509 586 * MOTE_MAC_NEW_CHANNEL_ANS]
GregCr 0:9be122c18509 587 * \param [in] p1 1st parameter ( optional depends on the command )
GregCr 0:9be122c18509 588 * \param [in] p2 2nd parameter ( optional depends on the command )
GregCr 0:9be122c18509 589 *
GregCr 0:9be122c18509 590 * \retval status Function status [0: OK, 1: Unknown command, 2: Buffer full]
GregCr 0:9be122c18509 591 */
GregCr 0:9be122c18509 592 static uint8_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
GregCr 0:9be122c18509 593 {
GregCr 0:9be122c18509 594 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
GregCr 0:9be122c18509 595 switch( cmd )
GregCr 0:9be122c18509 596 {
GregCr 0:9be122c18509 597 case MOTE_MAC_LINK_CHECK_REQ:
GregCr 0:9be122c18509 598 // No payload for this command
GregCr 0:9be122c18509 599 break;
GregCr 0:9be122c18509 600 case MOTE_MAC_LINK_ADR_ANS:
GregCr 0:9be122c18509 601 // Margin
GregCr 0:9be122c18509 602 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
GregCr 0:9be122c18509 603 break;
GregCr 0:9be122c18509 604 case MOTE_MAC_DUTY_CYCLE_ANS:
GregCr 0:9be122c18509 605 // No payload for this answer
GregCr 0:9be122c18509 606 break;
GregCr 0:9be122c18509 607 case MOTE_MAC_RX_PARAM_SETUP_ANS:
GregCr 0:9be122c18509 608 // Status: Datarate ACK, Channel ACK
GregCr 0:9be122c18509 609 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
GregCr 0:9be122c18509 610 break;
GregCr 0:9be122c18509 611 case MOTE_MAC_DEV_STATUS_ANS:
GregCr 0:9be122c18509 612 // 1st byte Battery
GregCr 0:9be122c18509 613 // 2nd byte Margin
GregCr 0:9be122c18509 614 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
GregCr 0:9be122c18509 615 MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
GregCr 0:9be122c18509 616 break;
GregCr 0:9be122c18509 617 case MOTE_MAC_NEW_CHANNEL_ANS:
GregCr 0:9be122c18509 618 // Status: Datarate range OK, Channel frequency OK
GregCr 0:9be122c18509 619 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
GregCr 0:9be122c18509 620 break;
GregCr 0:9be122c18509 621 case MOTE_MAC_RX_TIMING_SETUP_ANS:
GregCr 0:9be122c18509 622 // No payload for this answer
GregCr 0:9be122c18509 623 break;
GregCr 0:9be122c18509 624 default:
GregCr 0:9be122c18509 625 return 1;
GregCr 0:9be122c18509 626 }
GregCr 0:9be122c18509 627 if( MacCommandsBufferIndex <= 15 )
GregCr 0:9be122c18509 628 {
GregCr 0:9be122c18509 629 MacCommandsInNextTx = true;
GregCr 0:9be122c18509 630 return 0;
GregCr 0:9be122c18509 631 }
GregCr 0:9be122c18509 632 else
GregCr 0:9be122c18509 633 {
GregCr 0:9be122c18509 634 return 2;
GregCr 0:9be122c18509 635 }
GregCr 0:9be122c18509 636 }
GregCr 0:9be122c18509 637
GregCr 0:9be122c18509 638 // TODO: Add Documentation
GregCr 0:9be122c18509 639 static void LoRaMacNotify( LoRaMacEventFlags_t *flags, LoRaMacEventInfo_t *info )
GregCr 0:9be122c18509 640 {
GregCr 0:9be122c18509 641 if( ( LoRaMacEvents != NULL ) && ( LoRaMacEvents->MacEvent != NULL ) )
GregCr 0:9be122c18509 642 {
GregCr 0:9be122c18509 643 LoRaMacEvents->MacEvent( flags, info );
GregCr 0:9be122c18509 644 }
GregCr 0:9be122c18509 645 flags->Value = 0;
GregCr 0:9be122c18509 646 }
GregCr 0:9be122c18509 647
GregCr 0:9be122c18509 648 void LoRaMacInit( LoRaMacEvent_t *events )
GregCr 0:9be122c18509 649 {
GregCr 0:9be122c18509 650 LoRaMacEvents = events;
GregCr 0:9be122c18509 651
GregCr 0:9be122c18509 652 LoRaMacEventFlags.Value = 0;
GregCr 0:9be122c18509 653
GregCr 0:9be122c18509 654 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 655 LoRaMacEventInfo.TxNbRetries = 0;
GregCr 0:9be122c18509 656 LoRaMacEventInfo.TxDatarate = 7;
GregCr 0:9be122c18509 657 LoRaMacEventInfo.RxPort = 1;
GregCr 0:9be122c18509 658 LoRaMacEventInfo.RxBuffer = NULL;
GregCr 0:9be122c18509 659 LoRaMacEventInfo.RxBufferSize = 0;
GregCr 0:9be122c18509 660 LoRaMacEventInfo.RxRssi = 0;
GregCr 0:9be122c18509 661 LoRaMacEventInfo.RxSnr = 0;
GregCr 0:9be122c18509 662 LoRaMacEventInfo.Energy = 0;
GregCr 0:9be122c18509 663 LoRaMacEventInfo.DemodMargin = 0;
GregCr 0:9be122c18509 664 LoRaMacEventInfo.NbGateways = 0;
GregCr 0:9be122c18509 665 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 666
GregCr 0:9be122c18509 667 LoRaMacDeviceClass = CLASS_A;
GregCr 0:9be122c18509 668
GregCr 0:9be122c18509 669 UpLinkCounter = 1;
GregCr 0:9be122c18509 670 DownLinkCounter = 0;
GregCr 0:9be122c18509 671
GregCr 0:9be122c18509 672 IsLoRaMacNetworkJoined = false;
GregCr 0:9be122c18509 673 LoRaMacState = MAC_IDLE;
GregCr 0:9be122c18509 674
GregCr 0:9be122c18509 675 #if defined( USE_BAND_868 )
GregCr 0:9be122c18509 676 ChannelsMask = LC( 1 ) + LC( 2 ) + LC( 3 ) + LC( 4 ) + LC( 5 ) + LC( 6 ) + LC( 7 ) + LC( 8 ) + LC( 9 );
GregCr 0:9be122c18509 677 #else
GregCr 0:9be122c18509 678 ChannelsMask = LC( 1 ) + LC( 2 ) + LC( 3 );
GregCr 0:9be122c18509 679 #endif
GregCr 0:9be122c18509 680 ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
GregCr 0:9be122c18509 681 ChannelsDefaultDatarate = ChannelsDatarate = LORAMAC_DEFAULT_DATARATE;
GregCr 0:9be122c18509 682 ChannelsNbRep = 1;
GregCr 0:9be122c18509 683 ChannelsNbRepCounter = 0;
GregCr 0:9be122c18509 684
GregCr 0:9be122c18509 685 MaxDCycle = 0;
GregCr 0:9be122c18509 686 AggregatedDCycle = 1;
GregCr 0:9be122c18509 687 AggregatedLastTxDoneTime = 0;
GregCr 0:9be122c18509 688 AggregatedTimeOff = 0;
GregCr 0:9be122c18509 689
GregCr 0:9be122c18509 690 DutyCycleOn = true;
GregCr 0:9be122c18509 691
GregCr 0:9be122c18509 692 MaxRxWindow = MAX_RX_WINDOW;
GregCr 0:9be122c18509 693 ReceiveDelay1 = RECEIVE_DELAY1;
GregCr 0:9be122c18509 694 ReceiveDelay2 = RECEIVE_DELAY2;
GregCr 0:9be122c18509 695 JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1;
GregCr 0:9be122c18509 696 JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2;
GregCr 0:9be122c18509 697
GregCr 2:737ad7fbc97e 698 // MacStateCheckTimer.attach_us( &OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT );
GregCr 0:9be122c18509 699
GregCr 0:9be122c18509 700 // Random seed initialization
GregCr 0:9be122c18509 701 srand( RAND_SEED );
GregCr 0:9be122c18509 702
GregCr 0:9be122c18509 703 // Initialize channel index.
GregCr 0:9be122c18509 704 Channel = LORA_MAX_NB_CHANNELS;
GregCr 0:9be122c18509 705
GregCr 0:9be122c18509 706 PublicNetwork = true;
GregCr 0:9be122c18509 707 LoRaMacSetPublicNetwork( PublicNetwork );
GregCr 0:9be122c18509 708 Radio.Sleep( );
GregCr 0:9be122c18509 709 }
GregCr 0:9be122c18509 710
GregCr 0:9be122c18509 711 void LoRaMacSetAdrOn( bool enable )
GregCr 0:9be122c18509 712 {
GregCr 0:9be122c18509 713 AdrCtrlOn = enable;
GregCr 0:9be122c18509 714 }
GregCr 0:9be122c18509 715
GregCr 0:9be122c18509 716 void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey )
GregCr 0:9be122c18509 717 {
GregCr 0:9be122c18509 718 LoRaMacNetID = netID;
GregCr 0:9be122c18509 719 LoRaMacDevAddr = devAddr;
GregCr 0:9be122c18509 720 LoRaMacMemCpy( nwkSKey, LoRaMacNwkSKey, 16 );
GregCr 0:9be122c18509 721 LoRaMacMemCpy( appSKey, LoRaMacAppSKey, 16 );
GregCr 0:9be122c18509 722
GregCr 0:9be122c18509 723 IsLoRaMacNetworkJoined = true;
GregCr 0:9be122c18509 724 }
GregCr 0:9be122c18509 725
GregCr 0:9be122c18509 726 void LoRaMacMulticastChannelAdd( MulticastParams_t *channelParam )
GregCr 0:9be122c18509 727 {
GregCr 0:9be122c18509 728 // Reset downlink counter
GregCr 0:9be122c18509 729 channelParam->DownLinkCounter = 0;
GregCr 0:9be122c18509 730
GregCr 0:9be122c18509 731 if( MulticastChannels == NULL )
GregCr 0:9be122c18509 732 {
GregCr 0:9be122c18509 733 MulticastChannels = channelParam;
GregCr 0:9be122c18509 734 }
GregCr 0:9be122c18509 735 else
GregCr 0:9be122c18509 736 {
GregCr 0:9be122c18509 737 MulticastParams_t *cur = MulticastChannels;
GregCr 0:9be122c18509 738 while( cur->Next != NULL )
GregCr 0:9be122c18509 739 {
GregCr 0:9be122c18509 740 cur = cur->Next;
GregCr 0:9be122c18509 741 }
GregCr 0:9be122c18509 742 cur->Next = channelParam;
GregCr 0:9be122c18509 743 }
GregCr 0:9be122c18509 744 }
GregCr 0:9be122c18509 745
GregCr 0:9be122c18509 746 void LoRaMacMulticastChannelRemove( MulticastParams_t *channelParam )
GregCr 0:9be122c18509 747 {
GregCr 0:9be122c18509 748 MulticastParams_t *cur = NULL;
GregCr 0:9be122c18509 749
GregCr 0:9be122c18509 750 // Remove the front element
GregCr 0:9be122c18509 751 if( MulticastChannels == channelParam )
GregCr 0:9be122c18509 752 {
GregCr 0:9be122c18509 753 if( MulticastChannels != NULL )
GregCr 0:9be122c18509 754 {
GregCr 0:9be122c18509 755 cur = MulticastChannels;
GregCr 0:9be122c18509 756 MulticastChannels = MulticastChannels->Next;
GregCr 0:9be122c18509 757 cur->Next = NULL;
GregCr 0:9be122c18509 758 // Last node in the list
GregCr 0:9be122c18509 759 if( cur == MulticastChannels )
GregCr 0:9be122c18509 760 {
GregCr 0:9be122c18509 761 MulticastChannels = NULL;
GregCr 0:9be122c18509 762 }
GregCr 0:9be122c18509 763 }
GregCr 0:9be122c18509 764 return;
GregCr 0:9be122c18509 765 }
GregCr 0:9be122c18509 766
GregCr 0:9be122c18509 767 // Remove last element
GregCr 0:9be122c18509 768 if( channelParam->Next == NULL )
GregCr 0:9be122c18509 769 {
GregCr 0:9be122c18509 770 if( MulticastChannels != NULL )
GregCr 0:9be122c18509 771 {
GregCr 0:9be122c18509 772 cur = MulticastChannels;
GregCr 0:9be122c18509 773 MulticastParams_t *last = NULL;
GregCr 0:9be122c18509 774 while( cur->Next != NULL )
GregCr 0:9be122c18509 775 {
GregCr 0:9be122c18509 776 last = cur;
GregCr 0:9be122c18509 777 cur = cur->Next;
GregCr 0:9be122c18509 778 }
GregCr 0:9be122c18509 779 if( last != NULL )
GregCr 0:9be122c18509 780 {
GregCr 0:9be122c18509 781 last->Next = NULL;
GregCr 0:9be122c18509 782 }
GregCr 0:9be122c18509 783 // Last node in the list
GregCr 0:9be122c18509 784 if( cur == last )
GregCr 0:9be122c18509 785 {
GregCr 0:9be122c18509 786 MulticastChannels = NULL;
GregCr 0:9be122c18509 787 }
GregCr 0:9be122c18509 788 }
GregCr 0:9be122c18509 789 return;
GregCr 0:9be122c18509 790 }
GregCr 0:9be122c18509 791
GregCr 0:9be122c18509 792 // Remove a middle element
GregCr 0:9be122c18509 793 cur = MulticastChannels;
GregCr 0:9be122c18509 794 while( cur != NULL )
GregCr 0:9be122c18509 795 {
GregCr 0:9be122c18509 796 if( cur->Next == channelParam )
GregCr 0:9be122c18509 797 {
GregCr 0:9be122c18509 798 break;
GregCr 0:9be122c18509 799 }
GregCr 0:9be122c18509 800 cur = cur->Next;
GregCr 0:9be122c18509 801 }
GregCr 0:9be122c18509 802 if( cur != NULL )
GregCr 0:9be122c18509 803 {
GregCr 0:9be122c18509 804 MulticastParams_t *tmp = cur ->Next;
GregCr 0:9be122c18509 805 cur->Next = tmp->Next;
GregCr 0:9be122c18509 806 tmp->Next = NULL;
GregCr 0:9be122c18509 807 }
GregCr 0:9be122c18509 808 }
GregCr 0:9be122c18509 809
GregCr 0:9be122c18509 810 uint8_t LoRaMacJoinReq( uint8_t *devEui, uint8_t *appEui, uint8_t *appKey )
GregCr 0:9be122c18509 811 {
GregCr 0:9be122c18509 812 LoRaMacHeader_t macHdr;
GregCr 0:9be122c18509 813
GregCr 0:9be122c18509 814 LoRaMacDevEui = devEui;
GregCr 0:9be122c18509 815 LoRaMacAppEui = appEui;
GregCr 0:9be122c18509 816 LoRaMacAppKey = appKey;
GregCr 0:9be122c18509 817
GregCr 0:9be122c18509 818 macHdr.Value = 0;
GregCr 0:9be122c18509 819 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
GregCr 0:9be122c18509 820
GregCr 0:9be122c18509 821 IsLoRaMacNetworkJoined = false;
GregCr 0:9be122c18509 822 return LoRaMacSend( &macHdr, NULL, 0, NULL, 0 );
GregCr 0:9be122c18509 823 }
GregCr 0:9be122c18509 824
GregCr 0:9be122c18509 825 uint8_t LoRaMacLinkCheckReq( void )
GregCr 0:9be122c18509 826 {
GregCr 0:9be122c18509 827 return AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
GregCr 0:9be122c18509 828 }
GregCr 0:9be122c18509 829
GregCr 0:9be122c18509 830 uint8_t LoRaMacSendFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
GregCr 0:9be122c18509 831 {
GregCr 0:9be122c18509 832 LoRaMacHeader_t macHdr;
GregCr 0:9be122c18509 833
GregCr 0:9be122c18509 834 macHdr.Value = 0;
GregCr 0:9be122c18509 835 macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
GregCr 0:9be122c18509 836 return LoRaMacSend( &macHdr, NULL, fPort, fBuffer, fBufferSize );
GregCr 0:9be122c18509 837 }
GregCr 0:9be122c18509 838
GregCr 0:9be122c18509 839 uint8_t LoRaMacSendConfirmedFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize, uint8_t retries )
GregCr 0:9be122c18509 840 {
GregCr 0:9be122c18509 841 LoRaMacHeader_t macHdr;
GregCr 0:9be122c18509 842
GregCr 0:9be122c18509 843 if( AdrCtrlOn == false )
GregCr 0:9be122c18509 844 {
GregCr 0:9be122c18509 845 ChannelsDatarate = ChannelsDefaultDatarate;
GregCr 0:9be122c18509 846 }
GregCr 0:9be122c18509 847 AckTimeoutRetries = retries;
GregCr 0:9be122c18509 848 AckTimeoutRetriesCounter = 1;
GregCr 0:9be122c18509 849
GregCr 0:9be122c18509 850 macHdr.Value = 0;
GregCr 0:9be122c18509 851
GregCr 0:9be122c18509 852 macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
GregCr 0:9be122c18509 853 return LoRaMacSend( &macHdr, NULL, fPort, fBuffer, fBufferSize );
GregCr 0:9be122c18509 854 }
GregCr 0:9be122c18509 855
GregCr 0:9be122c18509 856 uint8_t LoRaMacSend( LoRaMacHeader_t *macHdr, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
GregCr 0:9be122c18509 857 {
GregCr 0:9be122c18509 858 LoRaMacFrameCtrl_t fCtrl;
GregCr 0:9be122c18509 859
GregCr 0:9be122c18509 860 fCtrl.Value = 0;
GregCr 0:9be122c18509 861
GregCr 0:9be122c18509 862 fCtrl.Bits.FOptsLen = 0;
GregCr 0:9be122c18509 863 fCtrl.Bits.FPending = 0;
GregCr 0:9be122c18509 864 fCtrl.Bits.Ack = false;
GregCr 0:9be122c18509 865 fCtrl.Bits.AdrAckReq = false;
GregCr 0:9be122c18509 866 fCtrl.Bits.Adr = AdrCtrlOn;
GregCr 0:9be122c18509 867
GregCr 0:9be122c18509 868 if( LoRaMacSetNextChannel( ) == 0 )
GregCr 0:9be122c18509 869 {
GregCr 0:9be122c18509 870 return LoRaMacSendOnChannel( Channels[Channel], macHdr, &fCtrl, fOpts, fPort, fBuffer, fBufferSize );
GregCr 0:9be122c18509 871 }
GregCr 0:9be122c18509 872 return 5;
GregCr 0:9be122c18509 873 }
GregCr 0:9be122c18509 874
GregCr 0:9be122c18509 875 uint8_t LoRaMacPrepareFrame( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
GregCr 0:9be122c18509 876 {
GregCr 0:9be122c18509 877 uint16_t i;
GregCr 0:9be122c18509 878 uint8_t pktHeaderLen = 0;
GregCr 0:9be122c18509 879 uint32_t mic = 0;
GregCr 0:9be122c18509 880
GregCr 0:9be122c18509 881 LoRaMacBufferPktLen = 0;
GregCr 0:9be122c18509 882
GregCr 0:9be122c18509 883 NodeAckRequested = false;
GregCr 0:9be122c18509 884
GregCr 0:9be122c18509 885 if( fBuffer == NULL )
GregCr 0:9be122c18509 886 {
GregCr 0:9be122c18509 887 fBufferSize = 0;
GregCr 0:9be122c18509 888 }
GregCr 0:9be122c18509 889
GregCr 0:9be122c18509 890 LoRaMacBuffer[pktHeaderLen++] = macHdr->Value;
GregCr 0:9be122c18509 891
GregCr 0:9be122c18509 892 switch( macHdr->Bits.MType )
GregCr 0:9be122c18509 893 {
GregCr 0:9be122c18509 894 case FRAME_TYPE_JOIN_REQ:
GregCr 0:9be122c18509 895 RxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME;
GregCr 0:9be122c18509 896 RxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME;
GregCr 0:9be122c18509 897
GregCr 0:9be122c18509 898 LoRaMacBufferPktLen = pktHeaderLen;
GregCr 0:9be122c18509 899
GregCr 0:9be122c18509 900 LoRaMacMemCpy( LoRaMacAppEui, LoRaMacBuffer + LoRaMacBufferPktLen, 8 );
GregCr 0:9be122c18509 901 LoRaMacBufferPktLen += 8;
GregCr 0:9be122c18509 902 LoRaMacMemCpy( LoRaMacDevEui, LoRaMacBuffer + LoRaMacBufferPktLen, 8 );
GregCr 0:9be122c18509 903 LoRaMacBufferPktLen += 8;
GregCr 0:9be122c18509 904
GregCr 0:9be122c18509 905 LoRaMacDevNonce = Radio.Random( );
GregCr 0:9be122c18509 906
GregCr 0:9be122c18509 907 LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF;
GregCr 0:9be122c18509 908 LoRaMacBuffer[LoRaMacBufferPktLen++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
GregCr 0:9be122c18509 909
GregCr 0:9be122c18509 910 LoRaMacJoinComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic );
GregCr 0:9be122c18509 911
GregCr 0:9be122c18509 912 LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF;
GregCr 0:9be122c18509 913 LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 8 ) & 0xFF;
GregCr 0:9be122c18509 914 LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 16 ) & 0xFF;
GregCr 0:9be122c18509 915 LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 24 ) & 0xFF;
GregCr 0:9be122c18509 916
GregCr 0:9be122c18509 917 break;
GregCr 0:9be122c18509 918 case FRAME_TYPE_DATA_CONFIRMED_UP:
GregCr 0:9be122c18509 919 NodeAckRequested = true;
GregCr 0:9be122c18509 920 //Intentional falltrough
GregCr 0:9be122c18509 921 case FRAME_TYPE_DATA_UNCONFIRMED_UP:
GregCr 0:9be122c18509 922 if( IsLoRaMacNetworkJoined == false )
GregCr 0:9be122c18509 923 {
GregCr 0:9be122c18509 924 return 2; // No network has been joined yet
GregCr 0:9be122c18509 925 }
GregCr 0:9be122c18509 926
GregCr 0:9be122c18509 927 RxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME;
GregCr 0:9be122c18509 928 RxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME;
GregCr 0:9be122c18509 929
GregCr 0:9be122c18509 930 if( fOpts == NULL )
GregCr 0:9be122c18509 931 {
GregCr 0:9be122c18509 932 fCtrl->Bits.FOptsLen = 0;
GregCr 0:9be122c18509 933 }
GregCr 0:9be122c18509 934
GregCr 0:9be122c18509 935 if( SrvAckRequested == true )
GregCr 0:9be122c18509 936 {
GregCr 0:9be122c18509 937 SrvAckRequested = false;
GregCr 0:9be122c18509 938 fCtrl->Bits.Ack = 1;
GregCr 0:9be122c18509 939 }
GregCr 0:9be122c18509 940
GregCr 0:9be122c18509 941 if( fCtrl->Bits.Adr == true )
GregCr 0:9be122c18509 942 {
GregCr 0:9be122c18509 943 if( ChannelsDatarate == LORAMAC_MIN_DATARATE )
GregCr 0:9be122c18509 944 {
GregCr 0:9be122c18509 945 AdrAckCounter = 0;
GregCr 0:9be122c18509 946 fCtrl->Bits.AdrAckReq = false;
GregCr 0:9be122c18509 947 }
GregCr 0:9be122c18509 948 else
GregCr 0:9be122c18509 949 {
GregCr 0:9be122c18509 950 if( AdrAckCounter > ADR_ACK_LIMIT )
GregCr 0:9be122c18509 951 {
GregCr 0:9be122c18509 952 fCtrl->Bits.AdrAckReq = true;
GregCr 0:9be122c18509 953 }
GregCr 0:9be122c18509 954 else
GregCr 0:9be122c18509 955 {
GregCr 0:9be122c18509 956 fCtrl->Bits.AdrAckReq = false;
GregCr 0:9be122c18509 957 }
GregCr 0:9be122c18509 958 if( AdrAckCounter > ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) )
GregCr 0:9be122c18509 959 {
GregCr 0:9be122c18509 960 AdrAckCounter = 0;
GregCr 0:9be122c18509 961 if( ChannelsDatarate > LORAMAC_MIN_DATARATE )
GregCr 0:9be122c18509 962 {
GregCr 0:9be122c18509 963 ChannelsDatarate--;
GregCr 0:9be122c18509 964 }
GregCr 0:9be122c18509 965 else
GregCr 0:9be122c18509 966 {
GregCr 0:9be122c18509 967 // Re-enable default channels LC1, LC2, LC3
GregCr 0:9be122c18509 968 ChannelsMask = ChannelsMask | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
GregCr 0:9be122c18509 969 }
GregCr 0:9be122c18509 970 }
GregCr 0:9be122c18509 971 }
GregCr 0:9be122c18509 972 }
GregCr 0:9be122c18509 973
GregCr 0:9be122c18509 974 LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF;
GregCr 0:9be122c18509 975 LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
GregCr 0:9be122c18509 976 LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
GregCr 0:9be122c18509 977 LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
GregCr 0:9be122c18509 978
GregCr 0:9be122c18509 979 LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value;
GregCr 0:9be122c18509 980
GregCr 0:9be122c18509 981 LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF;
GregCr 0:9be122c18509 982 LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF;
GregCr 0:9be122c18509 983
GregCr 0:9be122c18509 984 if( fOpts != NULL )
GregCr 0:9be122c18509 985 {
GregCr 0:9be122c18509 986 for( i = 0; i < fCtrl->Bits.FOptsLen; i++ )
GregCr 0:9be122c18509 987 {
GregCr 0:9be122c18509 988 LoRaMacBuffer[pktHeaderLen++] = fOpts[i];
GregCr 0:9be122c18509 989 }
GregCr 0:9be122c18509 990 }
GregCr 0:9be122c18509 991 if( ( MacCommandsBufferIndex + fCtrl->Bits.FOptsLen ) <= 15 )
GregCr 0:9be122c18509 992 {
GregCr 0:9be122c18509 993 if( MacCommandsInNextTx == true )
GregCr 0:9be122c18509 994 {
GregCr 0:9be122c18509 995 fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
GregCr 0:9be122c18509 996
GregCr 0:9be122c18509 997 // Update FCtrl field with new value of OptionsLength
GregCr 0:9be122c18509 998 LoRaMacBuffer[0x05] = fCtrl->Value;
GregCr 0:9be122c18509 999 for( i = 0; i < MacCommandsBufferIndex; i++ )
GregCr 0:9be122c18509 1000 {
GregCr 0:9be122c18509 1001 LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
GregCr 0:9be122c18509 1002 }
GregCr 0:9be122c18509 1003 }
GregCr 0:9be122c18509 1004 MacCommandsInNextTx = false;
GregCr 0:9be122c18509 1005 MacCommandsBufferIndex = 0;
GregCr 0:9be122c18509 1006 }
GregCr 0:9be122c18509 1007
GregCr 0:9be122c18509 1008 if( ( pktHeaderLen + fBufferSize ) > LORAMAC_PHY_MAXPAYLOAD )
GregCr 0:9be122c18509 1009 {
GregCr 0:9be122c18509 1010 return 3;
GregCr 0:9be122c18509 1011 }
GregCr 0:9be122c18509 1012
GregCr 0:9be122c18509 1013 if( fBuffer != NULL )
GregCr 0:9be122c18509 1014 {
GregCr 0:9be122c18509 1015 LoRaMacBuffer[pktHeaderLen] = fPort;
GregCr 0:9be122c18509 1016
GregCr 0:9be122c18509 1017 if( fPort == 0 )
GregCr 0:9be122c18509 1018 {
GregCr 0:9be122c18509 1019 LoRaMacPayloadEncrypt( (uint8_t*)fBuffer, fBufferSize, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
GregCr 0:9be122c18509 1020 }
GregCr 0:9be122c18509 1021 else
GregCr 0:9be122c18509 1022 {
GregCr 0:9be122c18509 1023 LoRaMacPayloadEncrypt( (uint8_t*)fBuffer, fBufferSize, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
GregCr 0:9be122c18509 1024 }
GregCr 0:9be122c18509 1025 LoRaMacMemCpy( LoRaMacPayload, LoRaMacBuffer + pktHeaderLen + 1, fBufferSize );
GregCr 0:9be122c18509 1026 }
GregCr 0:9be122c18509 1027 LoRaMacBufferPktLen = pktHeaderLen + 1 + fBufferSize;
GregCr 0:9be122c18509 1028
GregCr 0:9be122c18509 1029 LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic );
GregCr 0:9be122c18509 1030
GregCr 0:9be122c18509 1031 if( ( LoRaMacBufferPktLen + LORAMAC_MFR_LEN ) > LORAMAC_PHY_MAXPAYLOAD )
GregCr 0:9be122c18509 1032 {
GregCr 0:9be122c18509 1033 return 3;
GregCr 0:9be122c18509 1034 }
GregCr 0:9be122c18509 1035 LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF;
GregCr 0:9be122c18509 1036 LoRaMacBuffer[LoRaMacBufferPktLen + 1] = ( mic >> 8 ) & 0xFF;
GregCr 0:9be122c18509 1037 LoRaMacBuffer[LoRaMacBufferPktLen + 2] = ( mic >> 16 ) & 0xFF;
GregCr 0:9be122c18509 1038 LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF;
GregCr 0:9be122c18509 1039
GregCr 0:9be122c18509 1040 LoRaMacBufferPktLen += LORAMAC_MFR_LEN;
GregCr 0:9be122c18509 1041 break;
GregCr 0:9be122c18509 1042 default:
GregCr 0:9be122c18509 1043 return 4;
GregCr 0:9be122c18509 1044 }
GregCr 0:9be122c18509 1045
GregCr 0:9be122c18509 1046 return 0;
GregCr 0:9be122c18509 1047 }
GregCr 0:9be122c18509 1048
GregCr 0:9be122c18509 1049 uint8_t LoRaMacSendFrameOnChannel( ChannelParams_t channel )
GregCr 0:9be122c18509 1050 {
GregCr 0:9be122c18509 1051 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
GregCr 0:9be122c18509 1052 LoRaMacEventInfo.TxDatarate = Datarates[ChannelsDatarate];
GregCr 0:9be122c18509 1053
GregCr 0:9be122c18509 1054 Radio.SetChannel( channel.Frequency );
GregCr 0:9be122c18509 1055
GregCr 0:9be122c18509 1056 if( ChannelsDatarate == DR_7 )
GregCr 0:9be122c18509 1057 { // High Speed FSK channel
GregCr 0:9be122c18509 1058 Radio.SetTxConfig( MODEM_FSK, TxPowers[ChannelsTxPower], 25e3, 0, Datarates[ChannelsDatarate] * 1e3, 0, 5, false, true, 0, 0, false, 3e6 );
GregCr 0:9be122c18509 1059 TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1060 }
GregCr 0:9be122c18509 1061 else if( ChannelsDatarate == DR_6 )
GregCr 0:9be122c18509 1062 { // High speed LoRa channel
GregCr 0:9be122c18509 1063 Radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 1, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
GregCr 0:9be122c18509 1064 TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1065 }
GregCr 0:9be122c18509 1066 else
GregCr 0:9be122c18509 1067 { // Normal LoRa channel
GregCr 0:9be122c18509 1068 Radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 0, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
GregCr 0:9be122c18509 1069 TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1070 }
GregCr 0:9be122c18509 1071
GregCr 0:9be122c18509 1072 if( MaxDCycle == 255 )
GregCr 0:9be122c18509 1073 {
GregCr 0:9be122c18509 1074 return 6;
GregCr 0:9be122c18509 1075 }
GregCr 0:9be122c18509 1076 if( MaxDCycle == 0 )
GregCr 0:9be122c18509 1077 {
GregCr 0:9be122c18509 1078 AggregatedTimeOff = 0;
GregCr 0:9be122c18509 1079 }
GregCr 0:9be122c18509 1080
GregCr 0:9be122c18509 1081 LoRaMacState |= MAC_TX_RUNNING;
GregCr 0:9be122c18509 1082 // Starts the MAC layer status check timer
GregCr 0:9be122c18509 1083 MacStateCheckTimer.attach_us( &OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT );
GregCr 0:9be122c18509 1084
GregCr 0:9be122c18509 1085 if( MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) > ( TimerGetCurrentTime( ) ) )
GregCr 0:9be122c18509 1086 {
GregCr 0:9be122c18509 1087 // Schedule transmission
GregCr 0:9be122c18509 1088 TxDelayedTimer.attach_us( &OnTxDelayedTimerEvent, MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) );
GregCr 0:9be122c18509 1089 }
GregCr 0:9be122c18509 1090 else
GregCr 0:9be122c18509 1091 {
GregCr 0:9be122c18509 1092 // Send now
GregCr 0:9be122c18509 1093 Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1094 }
GregCr 0:9be122c18509 1095 return 0;
GregCr 0:9be122c18509 1096 }
GregCr 0:9be122c18509 1097
GregCr 0:9be122c18509 1098
GregCr 0:9be122c18509 1099 void OnTxDelayedTimerEvent( void )
GregCr 0:9be122c18509 1100 {
GregCr 2:737ad7fbc97e 1101 TxDelayedTimer.detach( );
GregCr 0:9be122c18509 1102 Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1103 }
GregCr 0:9be122c18509 1104
GregCr 0:9be122c18509 1105 uint8_t LoRaMacSendOnChannel( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
GregCr 0:9be122c18509 1106 {
GregCr 0:9be122c18509 1107 uint8_t status = 0;
GregCr 0:9be122c18509 1108
GregCr 0:9be122c18509 1109 if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
GregCr 0:9be122c18509 1110 {
GregCr 0:9be122c18509 1111 return 1; // MAC is busy transmitting a previous frame
GregCr 0:9be122c18509 1112 }
GregCr 0:9be122c18509 1113
GregCr 0:9be122c18509 1114 status = LoRaMacPrepareFrame( channel, macHdr, fCtrl, fOpts, fPort, fBuffer, fBufferSize );
GregCr 0:9be122c18509 1115 if( status != 0 )
GregCr 0:9be122c18509 1116 {
GregCr 0:9be122c18509 1117 return status;
GregCr 0:9be122c18509 1118 }
GregCr 0:9be122c18509 1119
GregCr 0:9be122c18509 1120 LoRaMacEventInfo.TxNbRetries = 0;
GregCr 0:9be122c18509 1121 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 1122
GregCr 0:9be122c18509 1123 return LoRaMacSendFrameOnChannel( channel );
GregCr 0:9be122c18509 1124 }
GregCr 0:9be122c18509 1125
GregCr 0:9be122c18509 1126 static void LoRaMacProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize )
GregCr 0:9be122c18509 1127 {
GregCr 0:9be122c18509 1128 while( macIndex < commandsSize )
GregCr 0:9be122c18509 1129 {
GregCr 0:9be122c18509 1130 // Decode Frame MAC commands
GregCr 0:9be122c18509 1131 switch( payload[macIndex++] )
GregCr 0:9be122c18509 1132 {
GregCr 0:9be122c18509 1133 case SRV_MAC_LINK_CHECK_ANS:
GregCr 0:9be122c18509 1134 LoRaMacEventFlags.Bits.LinkCheck = 1;
GregCr 0:9be122c18509 1135 LoRaMacEventInfo.DemodMargin = payload[macIndex++];
GregCr 0:9be122c18509 1136 LoRaMacEventInfo.NbGateways = payload[macIndex++];
GregCr 0:9be122c18509 1137 break;
GregCr 0:9be122c18509 1138 case SRV_MAC_LINK_ADR_REQ:
GregCr 0:9be122c18509 1139 {
GregCr 0:9be122c18509 1140 uint8_t i;
GregCr 0:9be122c18509 1141 uint8_t status = 0x07;
GregCr 0:9be122c18509 1142 uint16_t chMask = 0;
GregCr 0:9be122c18509 1143 int8_t txPower = 0;
GregCr 0:9be122c18509 1144 int8_t datarate = 0;
GregCr 0:9be122c18509 1145 uint8_t nbRep = 0;
GregCr 0:9be122c18509 1146 uint8_t chMaskCntl = 0;
GregCr 0:9be122c18509 1147
GregCr 0:9be122c18509 1148 datarate = payload[macIndex++];
GregCr 0:9be122c18509 1149 txPower = datarate & 0x0F;
GregCr 0:9be122c18509 1150 datarate = ( datarate >> 4 ) & 0x0F;
GregCr 0:9be122c18509 1151
GregCr 0:9be122c18509 1152 if( ( AdrCtrlOn == false ) &&
GregCr 0:9be122c18509 1153 ( ( ChannelsDatarate != datarate ) || ( ChannelsTxPower != txPower ) ) )
GregCr 0:9be122c18509 1154 { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower
GregCr 0:9be122c18509 1155 // Answer the server with fail status
GregCr 0:9be122c18509 1156 // Power ACK = 0
GregCr 0:9be122c18509 1157 // Data rate ACK = 0
GregCr 0:9be122c18509 1158 // Channel mask = 0
GregCr 0:9be122c18509 1159 AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
GregCr 0:9be122c18509 1160 break;
GregCr 0:9be122c18509 1161 }
GregCr 0:9be122c18509 1162 chMask = payload[macIndex++];
GregCr 0:9be122c18509 1163 chMask |= payload[macIndex++] << 8;
GregCr 0:9be122c18509 1164
GregCr 0:9be122c18509 1165 nbRep = payload[macIndex++];
GregCr 0:9be122c18509 1166 chMaskCntl = ( nbRep >> 4 ) & 0x07;
GregCr 0:9be122c18509 1167 nbRep &= 0x0F;
GregCr 0:9be122c18509 1168 if( nbRep == 0 )
GregCr 0:9be122c18509 1169 {
GregCr 0:9be122c18509 1170 nbRep = 1;
GregCr 0:9be122c18509 1171 }
GregCr 0:9be122c18509 1172 if( ( chMaskCntl == 0 ) && ( chMask == 0 ) )
GregCr 0:9be122c18509 1173 {
GregCr 0:9be122c18509 1174 status &= 0xFE; // Channel mask KO
GregCr 0:9be122c18509 1175 }
GregCr 0:9be122c18509 1176 else
GregCr 0:9be122c18509 1177 {
GregCr 0:9be122c18509 1178 for( i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
GregCr 0:9be122c18509 1179 {
GregCr 0:9be122c18509 1180 if( chMaskCntl == 6 )
GregCr 0:9be122c18509 1181 {
GregCr 0:9be122c18509 1182 if( Channels[i].Frequency != 0 )
GregCr 0:9be122c18509 1183 {
GregCr 0:9be122c18509 1184 chMask |= 1 << i;
GregCr 0:9be122c18509 1185 }
GregCr 0:9be122c18509 1186 }
GregCr 0:9be122c18509 1187 else
GregCr 0:9be122c18509 1188 {
GregCr 0:9be122c18509 1189 if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
GregCr 0:9be122c18509 1190 ( Channels[i].Frequency == 0 ) )
GregCr 0:9be122c18509 1191 {// Trying to enable an undefined channel
GregCr 0:9be122c18509 1192 status &= 0xFE; // Channel mask KO
GregCr 0:9be122c18509 1193 }
GregCr 0:9be122c18509 1194 }
GregCr 0:9be122c18509 1195 }
GregCr 0:9be122c18509 1196 }
GregCr 0:9be122c18509 1197 if( ( ( datarate < LORAMAC_MIN_DATARATE ) ||
GregCr 0:9be122c18509 1198 ( datarate > LORAMAC_MAX_DATARATE ) ) == true )
GregCr 0:9be122c18509 1199 {
GregCr 0:9be122c18509 1200 status &= 0xFD; // Datarate KO
GregCr 0:9be122c18509 1201 }
GregCr 0:9be122c18509 1202
GregCr 0:9be122c18509 1203 //
GregCr 0:9be122c18509 1204 // Remark MaxTxPower = 0 and MinTxPower = 5
GregCr 0:9be122c18509 1205 //
GregCr 0:9be122c18509 1206 if( ( ( LORAMAC_MAX_TX_POWER <= txPower ) &&
GregCr 0:9be122c18509 1207 ( txPower <= LORAMAC_MIN_TX_POWER ) ) == false )
GregCr 0:9be122c18509 1208 {
GregCr 0:9be122c18509 1209 status &= 0xFB; // TxPower KO
GregCr 0:9be122c18509 1210 }
GregCr 0:9be122c18509 1211 if( ( status & 0x07 ) == 0x07 )
GregCr 0:9be122c18509 1212 {
GregCr 0:9be122c18509 1213 ChannelsDatarate = datarate;
GregCr 0:9be122c18509 1214 ChannelsTxPower = txPower;
GregCr 0:9be122c18509 1215 ChannelsMask = chMask;
GregCr 0:9be122c18509 1216 ChannelsNbRep = nbRep;
GregCr 0:9be122c18509 1217 }
GregCr 0:9be122c18509 1218 AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );
GregCr 0:9be122c18509 1219 }
GregCr 0:9be122c18509 1220 break;
GregCr 0:9be122c18509 1221 case SRV_MAC_DUTY_CYCLE_REQ:
GregCr 0:9be122c18509 1222 MaxDCycle = payload[macIndex++];
GregCr 0:9be122c18509 1223 AggregatedDCycle = 1 << MaxDCycle;
GregCr 0:9be122c18509 1224 AddMacCommand( MOTE_MAC_DUTY_CYCLE_ANS, 0, 0 );
GregCr 0:9be122c18509 1225 break;
GregCr 0:9be122c18509 1226 case SRV_MAC_RX_PARAM_SETUP_REQ:
GregCr 0:9be122c18509 1227 {
GregCr 0:9be122c18509 1228 uint8_t status = 0x07;
GregCr 0:9be122c18509 1229 int8_t datarate = 0;
GregCr 0:9be122c18509 1230 int8_t drOffset = 0;
GregCr 0:9be122c18509 1231 uint32_t freq = 0;
GregCr 0:9be122c18509 1232
GregCr 0:9be122c18509 1233 drOffset = payload[macIndex++];
GregCr 0:9be122c18509 1234 datarate = drOffset & 0x0F;
GregCr 0:9be122c18509 1235 drOffset = ( drOffset >> 4 ) & 0x0F;
GregCr 0:9be122c18509 1236
GregCr 0:9be122c18509 1237 freq = payload[macIndex++];
GregCr 0:9be122c18509 1238 freq |= payload[macIndex++] << 8;
GregCr 0:9be122c18509 1239 freq |= payload[macIndex++] << 16;
GregCr 0:9be122c18509 1240 freq *= 100;
GregCr 0:9be122c18509 1241
GregCr 0:9be122c18509 1242 if( Radio.CheckRfFrequency( freq ) == false )
GregCr 0:9be122c18509 1243 {
GregCr 0:9be122c18509 1244 status &= 0xFE; // Channel frequency KO
GregCr 0:9be122c18509 1245 }
GregCr 0:9be122c18509 1246
GregCr 0:9be122c18509 1247 if( ( ( datarate < LORAMAC_MIN_DATARATE ) ||
GregCr 0:9be122c18509 1248 ( datarate > LORAMAC_MAX_DATARATE ) ) == true )
GregCr 0:9be122c18509 1249 {
GregCr 0:9be122c18509 1250 status &= 0xFD; // Datarate KO
GregCr 0:9be122c18509 1251 }
GregCr 0:9be122c18509 1252
GregCr 0:9be122c18509 1253 if( ( ( drOffset < 0 ) || ( drOffset > 5 ) ) == true )
GregCr 0:9be122c18509 1254 {
GregCr 0:9be122c18509 1255 status &= 0xFB; // Rx1DrOffset range KO
GregCr 0:9be122c18509 1256 }
GregCr 0:9be122c18509 1257
GregCr 0:9be122c18509 1258 if( ( status & 0x07 ) == 0x07 )
GregCr 0:9be122c18509 1259 {
GregCr 0:9be122c18509 1260 Rx2Channel.Datarate = datarate;
GregCr 0:9be122c18509 1261 Rx2Channel.Frequency = freq;
GregCr 0:9be122c18509 1262 Rx1DrOffset = drOffset;
GregCr 0:9be122c18509 1263 }
GregCr 0:9be122c18509 1264 AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 );
GregCr 0:9be122c18509 1265 }
GregCr 0:9be122c18509 1266 break;
GregCr 0:9be122c18509 1267 case SRV_MAC_DEV_STATUS_REQ:
GregCr 0:9be122c18509 1268 AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, BoardMeasureBatterieLevel( ), LoRaMacEventInfo.RxSnr );
GregCr 0:9be122c18509 1269 break;
GregCr 0:9be122c18509 1270 case SRV_MAC_NEW_CHANNEL_REQ:
GregCr 0:9be122c18509 1271 {
GregCr 0:9be122c18509 1272 uint8_t status = 0x03;
GregCr 0:9be122c18509 1273 int8_t channelIndex = 0;
GregCr 0:9be122c18509 1274 ChannelParams_t chParam;
GregCr 0:9be122c18509 1275
GregCr 0:9be122c18509 1276 channelIndex = payload[macIndex++];
GregCr 0:9be122c18509 1277 chParam.Frequency = payload[macIndex++];
GregCr 0:9be122c18509 1278 chParam.Frequency |= payload[macIndex++] << 8;
GregCr 0:9be122c18509 1279 chParam.Frequency |= payload[macIndex++] << 16;
GregCr 0:9be122c18509 1280 chParam.Frequency *= 100;
GregCr 0:9be122c18509 1281 chParam.DrRange.Value = payload[macIndex++];
GregCr 0:9be122c18509 1282
GregCr 0:9be122c18509 1283 if( ( channelIndex < 3 ) || ( channelIndex > LORA_MAX_NB_CHANNELS ) )
GregCr 0:9be122c18509 1284 {
GregCr 0:9be122c18509 1285 status &= 0xFE; // Channel frequency KO
GregCr 0:9be122c18509 1286 }
GregCr 0:9be122c18509 1287
GregCr 0:9be122c18509 1288 if( Radio.CheckRfFrequency( chParam.Frequency ) == false )
GregCr 0:9be122c18509 1289 {
GregCr 0:9be122c18509 1290 status &= 0xFE; // Channel frequency KO
GregCr 0:9be122c18509 1291 }
GregCr 0:9be122c18509 1292
GregCr 0:9be122c18509 1293 if( ( chParam.DrRange.Fields.Min > chParam.DrRange.Fields.Max ) ||
GregCr 0:9be122c18509 1294 ( ( ( LORAMAC_MIN_DATARATE <= chParam.DrRange.Fields.Min ) &&
GregCr 0:9be122c18509 1295 ( chParam.DrRange.Fields.Min <= LORAMAC_MAX_DATARATE ) ) == false ) ||
GregCr 0:9be122c18509 1296 ( ( ( LORAMAC_MIN_DATARATE <= chParam.DrRange.Fields.Max ) &&
GregCr 0:9be122c18509 1297 ( chParam.DrRange.Fields.Max <= LORAMAC_MAX_DATARATE ) ) == false ) )
GregCr 0:9be122c18509 1298 {
GregCr 0:9be122c18509 1299 status &= 0xFD; // Datarate range KO
GregCr 0:9be122c18509 1300 }
GregCr 0:9be122c18509 1301 if( ( status & 0x03 ) == 0x03 )
GregCr 0:9be122c18509 1302 {
GregCr 0:9be122c18509 1303 LoRaMacSetChannel( channelIndex, chParam );
GregCr 0:9be122c18509 1304 }
GregCr 0:9be122c18509 1305 AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
GregCr 0:9be122c18509 1306 }
GregCr 0:9be122c18509 1307 break;
GregCr 0:9be122c18509 1308 case SRV_MAC_RX_TIMING_SETUP_REQ:
GregCr 0:9be122c18509 1309 {
GregCr 0:9be122c18509 1310 uint8_t delay = payload[macIndex++] & 0x0F;
GregCr 0:9be122c18509 1311
GregCr 0:9be122c18509 1312 if( delay == 0 )
GregCr 0:9be122c18509 1313 {
GregCr 0:9be122c18509 1314 delay++;
GregCr 0:9be122c18509 1315 }
GregCr 0:9be122c18509 1316 ReceiveDelay1 = delay * 1e6;
GregCr 0:9be122c18509 1317 ReceiveDelay2 = ReceiveDelay1 + 1e6;
GregCr 0:9be122c18509 1318 AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
GregCr 0:9be122c18509 1319 }
GregCr 0:9be122c18509 1320 break;
GregCr 0:9be122c18509 1321 default:
GregCr 0:9be122c18509 1322 // Unknown command. ABORT MAC commands processing
GregCr 0:9be122c18509 1323 return;
GregCr 0:9be122c18509 1324 }
GregCr 0:9be122c18509 1325 }
GregCr 0:9be122c18509 1326 }
GregCr 0:9be122c18509 1327
GregCr 0:9be122c18509 1328 /*!
GregCr 0:9be122c18509 1329 * Function to be executed on Tx Done event
GregCr 0:9be122c18509 1330 */
GregCr 0:9be122c18509 1331 static void OnRadioTxDone( void )
GregCr 0:9be122c18509 1332 {
GregCr 0:9be122c18509 1333 uint64_t curTime = TimerGetCurrentTime( );
GregCr 0:9be122c18509 1334
GregCr 0:9be122c18509 1335 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1336 {
GregCr 0:9be122c18509 1337 Radio.Sleep( );
GregCr 0:9be122c18509 1338 }
GregCr 0:9be122c18509 1339 else
GregCr 0:9be122c18509 1340 {
GregCr 0:9be122c18509 1341 OnRxWindow2TimerEvent( );
GregCr 0:9be122c18509 1342 }
GregCr 0:9be122c18509 1343
GregCr 0:9be122c18509 1344 // Update Band Time OFF
GregCr 0:9be122c18509 1345 Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
GregCr 0:9be122c18509 1346 if( DutyCycleOn == true )
GregCr 0:9be122c18509 1347 {
GregCr 0:9be122c18509 1348 Bands[Channels[Channel].Band].TimeOff = TxTimeOnAir * Bands[Channels[Channel].Band].DCycle - TxTimeOnAir;
GregCr 0:9be122c18509 1349 }
GregCr 0:9be122c18509 1350 else
GregCr 0:9be122c18509 1351 {
GregCr 0:9be122c18509 1352 Bands[Channels[Channel].Band].TimeOff = 0;
GregCr 0:9be122c18509 1353 }
GregCr 0:9be122c18509 1354 // Update Agregated Time OFF
GregCr 0:9be122c18509 1355 AggregatedLastTxDoneTime = curTime;
GregCr 0:9be122c18509 1356 AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
GregCr 0:9be122c18509 1357
GregCr 0:9be122c18509 1358 if( IsRxWindowsEnabled == true )
GregCr 0:9be122c18509 1359 {
GregCr 0:9be122c18509 1360 RxWindowTimer1.attach_us( &OnRxWindow1TimerEvent, RxWindow1Delay );
GregCr 0:9be122c18509 1361
GregCr 0:9be122c18509 1362 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1363 {
GregCr 0:9be122c18509 1364 RxWindowTimer2.attach_us( &OnRxWindow2TimerEvent, RxWindow2Delay );
GregCr 0:9be122c18509 1365 }
GregCr 0:9be122c18509 1366 }
GregCr 0:9be122c18509 1367 else
GregCr 0:9be122c18509 1368 {
GregCr 0:9be122c18509 1369 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1370 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1371 }
GregCr 0:9be122c18509 1372
GregCr 0:9be122c18509 1373 if( NodeAckRequested == false )
GregCr 0:9be122c18509 1374 {
GregCr 0:9be122c18509 1375 ChannelsNbRepCounter++;
GregCr 0:9be122c18509 1376 }
GregCr 0:9be122c18509 1377 }
GregCr 0:9be122c18509 1378
GregCr 0:9be122c18509 1379 /*!
GregCr 0:9be122c18509 1380 * Function to be executed on Rx Done event
GregCr 0:9be122c18509 1381 */
GregCr 0:9be122c18509 1382 static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
GregCr 0:9be122c18509 1383 {
GregCr 0:9be122c18509 1384 LoRaMacHeader_t macHdr;
GregCr 0:9be122c18509 1385 LoRaMacFrameCtrl_t fCtrl;
GregCr 0:9be122c18509 1386
GregCr 0:9be122c18509 1387 uint8_t pktHeaderLen = 0;
GregCr 0:9be122c18509 1388 uint32_t address = 0;
GregCr 0:9be122c18509 1389 uint16_t sequenceCounter = 0;
GregCr 0:9be122c18509 1390 int32_t sequence = 0;
GregCr 0:9be122c18509 1391 uint8_t appPayloadStartIndex = 0;
GregCr 0:9be122c18509 1392 uint8_t port = 0xFF;
GregCr 0:9be122c18509 1393 uint8_t frameLen = 0;
GregCr 0:9be122c18509 1394 uint32_t mic = 0;
GregCr 0:9be122c18509 1395 uint32_t micRx = 0;
GregCr 0:9be122c18509 1396
GregCr 0:9be122c18509 1397 MulticastParams_t *curMulticastParams = NULL;
GregCr 0:9be122c18509 1398 uint8_t *nwkSKey = LoRaMacNwkSKey;
GregCr 0:9be122c18509 1399 uint8_t *appSKey = LoRaMacAppSKey;
GregCr 0:9be122c18509 1400 uint32_t downLinkCounter = 0;
GregCr 0:9be122c18509 1401
GregCr 0:9be122c18509 1402 bool isMicOk = false;
GregCr 0:9be122c18509 1403
GregCr 0:9be122c18509 1404 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1405 {
GregCr 0:9be122c18509 1406 Radio.Sleep( );
GregCr 0:9be122c18509 1407 }
GregCr 0:9be122c18509 1408 else
GregCr 0:9be122c18509 1409 {
GregCr 0:9be122c18509 1410 if( LoRaMacEventFlags.Bits.RxSlot == 0 )
GregCr 0:9be122c18509 1411 {
GregCr 0:9be122c18509 1412 OnRxWindow2TimerEvent( );
GregCr 0:9be122c18509 1413 }
GregCr 0:9be122c18509 1414 }
GregCr 2:737ad7fbc97e 1415 RxWindowTimer2.detach( ); // Timer is removed anyway in functions above
GregCr 0:9be122c18509 1416
GregCr 0:9be122c18509 1417 macHdr.Value = payload[pktHeaderLen++];
GregCr 0:9be122c18509 1418
GregCr 0:9be122c18509 1419 switch( macHdr.Bits.MType )
GregCr 0:9be122c18509 1420 {
GregCr 0:9be122c18509 1421 case FRAME_TYPE_JOIN_ACCEPT:
GregCr 0:9be122c18509 1422 if( IsLoRaMacNetworkJoined == true )
GregCr 0:9be122c18509 1423 {
GregCr 0:9be122c18509 1424 break;
GregCr 0:9be122c18509 1425 }
GregCr 0:9be122c18509 1426 LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 );
GregCr 0:9be122c18509 1427
GregCr 0:9be122c18509 1428 LoRaMacRxPayload[0] = macHdr.Value;
GregCr 0:9be122c18509 1429
GregCr 0:9be122c18509 1430 LoRaMacJoinComputeMic( LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic );
GregCr 0:9be122c18509 1431
GregCr 0:9be122c18509 1432 micRx |= LoRaMacRxPayload[size - LORAMAC_MFR_LEN];
GregCr 0:9be122c18509 1433 micRx |= ( LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8 );
GregCr 0:9be122c18509 1434 micRx |= ( LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 );
GregCr 0:9be122c18509 1435 micRx |= ( LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 );
GregCr 0:9be122c18509 1436
GregCr 0:9be122c18509 1437 if( micRx == mic )
GregCr 0:9be122c18509 1438 {
GregCr 0:9be122c18509 1439 LoRaMacEventFlags.Bits.Rx = 1;
GregCr 0:9be122c18509 1440 LoRaMacEventInfo.RxSnr = snr;
GregCr 0:9be122c18509 1441 LoRaMacEventInfo.RxRssi = rssi;
GregCr 0:9be122c18509 1442
GregCr 0:9be122c18509 1443 LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
GregCr 0:9be122c18509 1444
GregCr 0:9be122c18509 1445 LoRaMacNetID = LoRaMacRxPayload[4];
GregCr 0:9be122c18509 1446 LoRaMacNetID |= ( LoRaMacRxPayload[5] << 8 );
GregCr 0:9be122c18509 1447 LoRaMacNetID |= ( LoRaMacRxPayload[6] << 16 );
GregCr 0:9be122c18509 1448
GregCr 0:9be122c18509 1449 LoRaMacDevAddr = LoRaMacRxPayload[7];
GregCr 0:9be122c18509 1450 LoRaMacDevAddr |= ( LoRaMacRxPayload[8] << 8 );
GregCr 0:9be122c18509 1451 LoRaMacDevAddr |= ( LoRaMacRxPayload[9] << 16 );
GregCr 0:9be122c18509 1452 LoRaMacDevAddr |= ( LoRaMacRxPayload[10] << 24 );
GregCr 0:9be122c18509 1453
GregCr 0:9be122c18509 1454 // DLSettings
GregCr 0:9be122c18509 1455 Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07;
GregCr 0:9be122c18509 1456 Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
GregCr 0:9be122c18509 1457
GregCr 0:9be122c18509 1458 // RxDelay
GregCr 0:9be122c18509 1459 ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F );
GregCr 0:9be122c18509 1460 if( ReceiveDelay1 == 0 )
GregCr 0:9be122c18509 1461 {
GregCr 0:9be122c18509 1462 ReceiveDelay1 = 1;
GregCr 0:9be122c18509 1463 }
GregCr 0:9be122c18509 1464 ReceiveDelay1 *= 1e6;
GregCr 0:9be122c18509 1465 ReceiveDelay2 = ReceiveDelay1 + 1e6;
GregCr 0:9be122c18509 1466
GregCr 0:9be122c18509 1467 //CFList
GregCr 0:9be122c18509 1468 if( ( size - 1 ) > 16 )
GregCr 0:9be122c18509 1469 {
GregCr 0:9be122c18509 1470 ChannelParams_t param;
GregCr 0:9be122c18509 1471 param.DrRange.Value = ( DR_5 << 4 ) | DR_0;
GregCr 0:9be122c18509 1472
GregCr 0:9be122c18509 1473 for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 )
GregCr 0:9be122c18509 1474 {
GregCr 0:9be122c18509 1475 param.Frequency = ( LoRaMacRxPayload[13 + j] | ( LoRaMacRxPayload[14 + j] << 8 ) | ( LoRaMacRxPayload[15 + j] << 16 ) ) * 100;
GregCr 0:9be122c18509 1476 LoRaMacSetChannel( i, param );
GregCr 0:9be122c18509 1477 }
GregCr 0:9be122c18509 1478 }
GregCr 0:9be122c18509 1479
GregCr 0:9be122c18509 1480 LoRaMacEventFlags.Bits.JoinAccept = 1;
GregCr 0:9be122c18509 1481 IsLoRaMacNetworkJoined = true;
GregCr 0:9be122c18509 1482 ChannelsDatarate = ChannelsDefaultDatarate;
GregCr 0:9be122c18509 1483 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1484 }
GregCr 0:9be122c18509 1485 else
GregCr 0:9be122c18509 1486 {
GregCr 0:9be122c18509 1487 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
GregCr 0:9be122c18509 1488 }
GregCr 0:9be122c18509 1489
GregCr 0:9be122c18509 1490 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1491 break;
GregCr 0:9be122c18509 1492 case FRAME_TYPE_DATA_CONFIRMED_DOWN:
GregCr 0:9be122c18509 1493 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
GregCr 0:9be122c18509 1494 {
GregCr 0:9be122c18509 1495 address = payload[pktHeaderLen++];
GregCr 0:9be122c18509 1496 address |= ( payload[pktHeaderLen++] << 8 );
GregCr 0:9be122c18509 1497 address |= ( payload[pktHeaderLen++] << 16 );
GregCr 0:9be122c18509 1498 address |= ( payload[pktHeaderLen++] << 24 );
GregCr 0:9be122c18509 1499
GregCr 0:9be122c18509 1500 if( address != LoRaMacDevAddr )
GregCr 0:9be122c18509 1501 {
GregCr 0:9be122c18509 1502 curMulticastParams = MulticastChannels;
GregCr 0:9be122c18509 1503 while( curMulticastParams != NULL )
GregCr 0:9be122c18509 1504 {
GregCr 0:9be122c18509 1505 if( address == curMulticastParams->Address )
GregCr 0:9be122c18509 1506 {
GregCr 0:9be122c18509 1507 LoRaMacEventFlags.Bits.Multicast = 1;
GregCr 0:9be122c18509 1508 nwkSKey = curMulticastParams->NwkSKey;
GregCr 0:9be122c18509 1509 appSKey = curMulticastParams->AppSKey;
GregCr 0:9be122c18509 1510 downLinkCounter = curMulticastParams->DownLinkCounter;
GregCr 0:9be122c18509 1511 break;
GregCr 0:9be122c18509 1512 }
GregCr 0:9be122c18509 1513 curMulticastParams = curMulticastParams->Next;
GregCr 0:9be122c18509 1514 }
GregCr 0:9be122c18509 1515 if( LoRaMacEventFlags.Bits.Multicast == 0 )
GregCr 0:9be122c18509 1516 {
GregCr 0:9be122c18509 1517 // We are not the destination of this frame.
GregCr 0:9be122c18509 1518 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1519 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
GregCr 0:9be122c18509 1520 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1521 return;
GregCr 0:9be122c18509 1522 }
GregCr 0:9be122c18509 1523 }
GregCr 0:9be122c18509 1524 else
GregCr 0:9be122c18509 1525 {
GregCr 0:9be122c18509 1526 LoRaMacEventFlags.Bits.Multicast = 0;
GregCr 0:9be122c18509 1527 nwkSKey = LoRaMacNwkSKey;
GregCr 0:9be122c18509 1528 appSKey = LoRaMacAppSKey;
GregCr 0:9be122c18509 1529 downLinkCounter = DownLinkCounter;
GregCr 0:9be122c18509 1530 }
GregCr 0:9be122c18509 1531
GregCr 0:9be122c18509 1532 if( LoRaMacDeviceClass != CLASS_A )
GregCr 0:9be122c18509 1533 {
GregCr 0:9be122c18509 1534 LoRaMacState |= MAC_RX;
GregCr 0:9be122c18509 1535 // Starts the MAC layer status check timer
GregCr 0:9be122c18509 1536 MacStateCheckTimer.attach_us( &OnMacStateCheckTimerEvent , MAC_STATE_CHECK_TIMEOUT );
GregCr 0:9be122c18509 1537 }
GregCr 0:9be122c18509 1538 fCtrl.Value = payload[pktHeaderLen++];
GregCr 0:9be122c18509 1539
GregCr 0:9be122c18509 1540 sequenceCounter |= payload[pktHeaderLen++];
GregCr 0:9be122c18509 1541 sequenceCounter |= payload[pktHeaderLen++] << 8;
GregCr 0:9be122c18509 1542
GregCr 0:9be122c18509 1543 appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
GregCr 0:9be122c18509 1544
GregCr 0:9be122c18509 1545 micRx |= payload[size - LORAMAC_MFR_LEN];
GregCr 0:9be122c18509 1546 micRx |= ( payload[size - LORAMAC_MFR_LEN + 1] << 8 );
GregCr 0:9be122c18509 1547 micRx |= ( payload[size - LORAMAC_MFR_LEN + 2] << 16 );
GregCr 0:9be122c18509 1548 micRx |= ( payload[size - LORAMAC_MFR_LEN + 3] << 24 );
GregCr 0:9be122c18509 1549
GregCr 0:9be122c18509 1550 sequence = ( int32_t )sequenceCounter - ( int32_t )( downLinkCounter & 0xFFFF );
GregCr 0:9be122c18509 1551 if( sequence < 0 )
GregCr 0:9be122c18509 1552 {
GregCr 0:9be122c18509 1553 // sequence reset or roll over happened
GregCr 0:9be122c18509 1554 downLinkCounter = ( downLinkCounter & 0xFFFF0000 ) | ( sequenceCounter + ( uint32_t )0x10000 );
GregCr 0:9be122c18509 1555 LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
GregCr 0:9be122c18509 1556 if( micRx == mic )
GregCr 0:9be122c18509 1557 {
GregCr 0:9be122c18509 1558 isMicOk = true;
GregCr 0:9be122c18509 1559 }
GregCr 0:9be122c18509 1560 else
GregCr 0:9be122c18509 1561 {
GregCr 0:9be122c18509 1562 isMicOk = false;
GregCr 0:9be122c18509 1563 // sequence reset
GregCr 0:9be122c18509 1564 if( LoRaMacEventFlags.Bits.Multicast == 1 )
GregCr 0:9be122c18509 1565 {
GregCr 0:9be122c18509 1566 curMulticastParams->DownLinkCounter = downLinkCounter = sequenceCounter;
GregCr 0:9be122c18509 1567 }
GregCr 0:9be122c18509 1568 else
GregCr 0:9be122c18509 1569 {
GregCr 0:9be122c18509 1570 DownLinkCounter = downLinkCounter = sequenceCounter;
GregCr 0:9be122c18509 1571 }
GregCr 0:9be122c18509 1572 LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
GregCr 0:9be122c18509 1573 }
GregCr 0:9be122c18509 1574 }
GregCr 0:9be122c18509 1575 else
GregCr 0:9be122c18509 1576 {
GregCr 0:9be122c18509 1577 downLinkCounter = ( downLinkCounter & 0xFFFF0000 ) | sequenceCounter;
GregCr 0:9be122c18509 1578 LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
GregCr 0:9be122c18509 1579 }
GregCr 0:9be122c18509 1580
GregCr 0:9be122c18509 1581 if( ( isMicOk == true ) ||
GregCr 0:9be122c18509 1582 ( micRx == mic ) )
GregCr 0:9be122c18509 1583 {
GregCr 0:9be122c18509 1584 LoRaMacEventFlags.Bits.Rx = 1;
GregCr 0:9be122c18509 1585 LoRaMacEventInfo.RxSnr = snr;
GregCr 0:9be122c18509 1586 LoRaMacEventInfo.RxRssi = rssi;
GregCr 0:9be122c18509 1587 LoRaMacEventInfo.RxBufferSize = 0;
GregCr 0:9be122c18509 1588 AdrAckCounter = 0;
GregCr 0:9be122c18509 1589 if( LoRaMacEventFlags.Bits.Multicast == 1 )
GregCr 0:9be122c18509 1590 {
GregCr 0:9be122c18509 1591 curMulticastParams->DownLinkCounter = downLinkCounter;
GregCr 0:9be122c18509 1592 }
GregCr 0:9be122c18509 1593 else
GregCr 0:9be122c18509 1594 {
GregCr 0:9be122c18509 1595 DownLinkCounter = downLinkCounter;
GregCr 0:9be122c18509 1596 }
GregCr 0:9be122c18509 1597
GregCr 0:9be122c18509 1598 if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
GregCr 0:9be122c18509 1599 {
GregCr 0:9be122c18509 1600 SrvAckRequested = true;
GregCr 0:9be122c18509 1601 }
GregCr 0:9be122c18509 1602 else
GregCr 0:9be122c18509 1603 {
GregCr 0:9be122c18509 1604 SrvAckRequested = false;
GregCr 0:9be122c18509 1605 }
GregCr 0:9be122c18509 1606 // Check if the frame is an acknowledgement
GregCr 0:9be122c18509 1607 if( fCtrl.Bits.Ack == 1 )
GregCr 0:9be122c18509 1608 {
GregCr 0:9be122c18509 1609 LoRaMacEventInfo.TxAckReceived = true;
GregCr 0:9be122c18509 1610
GregCr 0:9be122c18509 1611 // Stop the AckTimeout timer as no more retransmissions
GregCr 0:9be122c18509 1612 // are needed.
GregCr 0:9be122c18509 1613 AckTimeoutTimer.detach( );
GregCr 0:9be122c18509 1614 }
GregCr 0:9be122c18509 1615 else
GregCr 0:9be122c18509 1616 {
GregCr 0:9be122c18509 1617 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 1618 if( AckTimeoutRetriesCounter > AckTimeoutRetries )
GregCr 0:9be122c18509 1619 {
GregCr 0:9be122c18509 1620 // Stop the AckTimeout timer as no more retransmissions
GregCr 0:9be122c18509 1621 // are needed.
GregCr 0:9be122c18509 1622 AckTimeoutTimer.detach( );
GregCr 0:9be122c18509 1623 }
GregCr 0:9be122c18509 1624 }
GregCr 0:9be122c18509 1625
GregCr 0:9be122c18509 1626 if( fCtrl.Bits.FOptsLen > 0 )
GregCr 0:9be122c18509 1627 {
GregCr 0:9be122c18509 1628 // Decode Options field MAC commands
GregCr 0:9be122c18509 1629 LoRaMacProcessMacCommands( payload, 8, appPayloadStartIndex );
GregCr 0:9be122c18509 1630 }
GregCr 0:9be122c18509 1631
GregCr 0:9be122c18509 1632 if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
GregCr 0:9be122c18509 1633 {
GregCr 0:9be122c18509 1634 port = payload[appPayloadStartIndex++];
GregCr 0:9be122c18509 1635 frameLen = ( size - 4 ) - appPayloadStartIndex;
GregCr 0:9be122c18509 1636
GregCr 0:9be122c18509 1637 if( port == 0 )
GregCr 0:9be122c18509 1638 {
GregCr 0:9be122c18509 1639 LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
GregCr 0:9be122c18509 1640 frameLen,
GregCr 0:9be122c18509 1641 nwkSKey,
GregCr 0:9be122c18509 1642 address,
GregCr 0:9be122c18509 1643 DOWN_LINK,
GregCr 0:9be122c18509 1644 downLinkCounter,
GregCr 0:9be122c18509 1645 LoRaMacRxPayload );
GregCr 0:9be122c18509 1646
GregCr 0:9be122c18509 1647 // Decode frame payload MAC commands
GregCr 0:9be122c18509 1648 LoRaMacProcessMacCommands( LoRaMacRxPayload, 0, frameLen );
GregCr 0:9be122c18509 1649 }
GregCr 0:9be122c18509 1650 else
GregCr 0:9be122c18509 1651 {
GregCr 0:9be122c18509 1652 LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
GregCr 0:9be122c18509 1653 frameLen,
GregCr 0:9be122c18509 1654 appSKey,
GregCr 0:9be122c18509 1655 address,
GregCr 0:9be122c18509 1656 DOWN_LINK,
GregCr 0:9be122c18509 1657 downLinkCounter,
GregCr 0:9be122c18509 1658 LoRaMacRxPayload );
GregCr 0:9be122c18509 1659
GregCr 0:9be122c18509 1660 LoRaMacEventFlags.Bits.RxData = 1;
GregCr 0:9be122c18509 1661 LoRaMacEventInfo.RxPort = port;
GregCr 0:9be122c18509 1662 LoRaMacEventInfo.RxBuffer = LoRaMacRxPayload;
GregCr 0:9be122c18509 1663 LoRaMacEventInfo.RxBufferSize = frameLen;
GregCr 0:9be122c18509 1664 }
GregCr 0:9be122c18509 1665 }
GregCr 0:9be122c18509 1666
GregCr 0:9be122c18509 1667 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1668 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1669 }
GregCr 0:9be122c18509 1670 else
GregCr 0:9be122c18509 1671 {
GregCr 0:9be122c18509 1672 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 1673
GregCr 0:9be122c18509 1674 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1675 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
GregCr 0:9be122c18509 1676 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1677 }
GregCr 0:9be122c18509 1678 }
GregCr 0:9be122c18509 1679 break;
GregCr 0:9be122c18509 1680 case FRAME_TYPE_PROPRIETARY:
GregCr 0:9be122c18509 1681 //Intentional falltrough
GregCr 0:9be122c18509 1682 default:
GregCr 0:9be122c18509 1683 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1684 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
GregCr 0:9be122c18509 1685 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1686 break;
GregCr 0:9be122c18509 1687 }
GregCr 0:9be122c18509 1688 }
GregCr 0:9be122c18509 1689
GregCr 0:9be122c18509 1690 /*!
GregCr 0:9be122c18509 1691 * Function executed on Radio Tx Timeout event
GregCr 0:9be122c18509 1692 */
GregCr 0:9be122c18509 1693 static void OnRadioTxTimeout( void )
GregCr 1:0a272b37c6cd 1694 {
GregCr 0:9be122c18509 1695 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1696 {
GregCr 0:9be122c18509 1697 Radio.Sleep( );
GregCr 0:9be122c18509 1698 }
GregCr 0:9be122c18509 1699 else
GregCr 0:9be122c18509 1700 {
GregCr 0:9be122c18509 1701 OnRxWindow2TimerEvent( );
GregCr 0:9be122c18509 1702 }
GregCr 0:9be122c18509 1703
GregCr 0:9be122c18509 1704 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1705 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
GregCr 0:9be122c18509 1706 }
GregCr 0:9be122c18509 1707
GregCr 0:9be122c18509 1708 /*!
GregCr 0:9be122c18509 1709 * Function executed on Radio Rx Timeout event
GregCr 0:9be122c18509 1710 */
GregCr 0:9be122c18509 1711 static void OnRadioRxTimeout( void )
GregCr 1:0a272b37c6cd 1712 {
GregCr 0:9be122c18509 1713 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1714 {
GregCr 0:9be122c18509 1715 Radio.Sleep( );
GregCr 0:9be122c18509 1716 }
GregCr 0:9be122c18509 1717 if( LoRaMacEventFlags.Bits.RxSlot == 1 )
GregCr 0:9be122c18509 1718 {
GregCr 0:9be122c18509 1719 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1720 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
GregCr 0:9be122c18509 1721 }
GregCr 0:9be122c18509 1722 }
GregCr 0:9be122c18509 1723
GregCr 0:9be122c18509 1724 /*!
GregCr 0:9be122c18509 1725 * Function executed on Radio Rx Error event
GregCr 0:9be122c18509 1726 */
GregCr 0:9be122c18509 1727 static void OnRadioRxError( void )
GregCr 1:0a272b37c6cd 1728 {
GregCr 0:9be122c18509 1729 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1730 {
GregCr 0:9be122c18509 1731 Radio.Sleep( );
GregCr 0:9be122c18509 1732 }
GregCr 0:9be122c18509 1733 if( LoRaMacEventFlags.Bits.RxSlot == 1 )
GregCr 0:9be122c18509 1734 {
GregCr 0:9be122c18509 1735 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1736 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
GregCr 0:9be122c18509 1737 }
GregCr 0:9be122c18509 1738 }
GregCr 0:9be122c18509 1739
GregCr 0:9be122c18509 1740 /*!
GregCr 0:9be122c18509 1741 * Initializes and opens the reception window
GregCr 0:9be122c18509 1742 *
GregCr 0:9be122c18509 1743 * \param [IN] freq window channel frequency
GregCr 0:9be122c18509 1744 * \param [IN] datarate window channel datarate
GregCr 0:9be122c18509 1745 * \param [IN] bandwidth window channel bandwidth
GregCr 0:9be122c18509 1746 * \param [IN] timeout window channel timeout
GregCr 0:9be122c18509 1747 */
GregCr 0:9be122c18509 1748 void LoRaMacRxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous )
GregCr 0:9be122c18509 1749 {
GregCr 0:9be122c18509 1750 if( Radio.GetStatus( ) == IDLE )
GregCr 0:9be122c18509 1751 {
GregCr 0:9be122c18509 1752 Radio.SetChannel( freq );
GregCr 0:9be122c18509 1753 if( datarate == DR_7 )
GregCr 0:9be122c18509 1754 {
GregCr 0:9be122c18509 1755 Radio.SetRxConfig( MODEM_FSK, 50e3, Datarates[datarate] * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, rxContinuous );
GregCr 0:9be122c18509 1756 }
GregCr 0:9be122c18509 1757 else
GregCr 0:9be122c18509 1758 {
GregCr 0:9be122c18509 1759 Radio.SetRxConfig( MODEM_LORA, bandwidth, Datarates[datarate], 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous );
GregCr 0:9be122c18509 1760 }
GregCr 0:9be122c18509 1761 if( rxContinuous == false )
GregCr 0:9be122c18509 1762 {
GregCr 0:9be122c18509 1763 Radio.Rx( MaxRxWindow );
GregCr 0:9be122c18509 1764 }
GregCr 0:9be122c18509 1765 else
GregCr 0:9be122c18509 1766 {
GregCr 0:9be122c18509 1767 Radio.Rx( 0 ); // Continuous mode
GregCr 0:9be122c18509 1768 }
GregCr 0:9be122c18509 1769 }
GregCr 0:9be122c18509 1770 }
GregCr 0:9be122c18509 1771
GregCr 0:9be122c18509 1772 /*!
GregCr 0:9be122c18509 1773 * Function executed on first Rx window timer event
GregCr 0:9be122c18509 1774 */
GregCr 0:9be122c18509 1775 static void OnRxWindow1TimerEvent( void )
GregCr 0:9be122c18509 1776 {
GregCr 3:675d14219ad5 1777 uint16_t symbTimeout = 20; // DR_2, DR_1, DR_0
GregCr 0:9be122c18509 1778 int8_t datarate = 0;
GregCr 0:9be122c18509 1779 uint32_t bandwidth = 0; // LoRa 125 kHz
GregCr 0:9be122c18509 1780
GregCr 1:0a272b37c6cd 1781 RxWindowTimer1.detach( );
GregCr 0:9be122c18509 1782
GregCr 0:9be122c18509 1783 datarate = ChannelsDatarate - Rx1DrOffset;
GregCr 0:9be122c18509 1784 if( datarate < 0 )
GregCr 0:9be122c18509 1785 {
GregCr 0:9be122c18509 1786 datarate = DR_0;
GregCr 0:9be122c18509 1787 }
GregCr 0:9be122c18509 1788
GregCr 0:9be122c18509 1789 // For higher datarates, we increase the number of symbols generating a Rx Timeout
GregCr 0:9be122c18509 1790 if( datarate >= DR_3 )
GregCr 0:9be122c18509 1791 { // DR_6, DR_5, DR_4, DR_3
Alliance 5:50aab2960e8c 1792 symbTimeout = 80;
GregCr 0:9be122c18509 1793 }
GregCr 0:9be122c18509 1794 if( datarate == DR_6 )
GregCr 0:9be122c18509 1795 {// LoRa 250 kHz
GregCr 0:9be122c18509 1796 bandwidth = 1;
GregCr 0:9be122c18509 1797 }
GregCr 0:9be122c18509 1798 LoRaMacEventFlags.Bits.RxSlot = 0;
GregCr 0:9be122c18509 1799 LoRaMacRxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false );
GregCr 0:9be122c18509 1800 }
GregCr 0:9be122c18509 1801
GregCr 0:9be122c18509 1802 /*!
GregCr 0:9be122c18509 1803 * Function executed on second Rx window timer event
GregCr 0:9be122c18509 1804 */
GregCr 0:9be122c18509 1805 static void OnRxWindow2TimerEvent( void )
GregCr 0:9be122c18509 1806 {
GregCr 1:0a272b37c6cd 1807 RxWindowTimer2.detach( );
GregCr 0:9be122c18509 1808
GregCr 0:9be122c18509 1809 if( NodeAckRequested == true )
GregCr 0:9be122c18509 1810 {
GregCr 0:9be122c18509 1811 AckTimeoutTimer.attach_us( &OnAckTimeoutTimerEvent, ACK_TIMEOUT + randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
GregCr 0:9be122c18509 1812 }
GregCr 0:9be122c18509 1813
GregCr 3:675d14219ad5 1814 uint16_t symbTimeout = 20; // DR_2, DR_1, DR_0
GregCr 0:9be122c18509 1815 uint32_t bandwidth = 0; // LoRa 125 kHz
GregCr 0:9be122c18509 1816
GregCr 0:9be122c18509 1817 // For higher datarates, we increase the number of symbols generating a Rx Timeout
GregCr 0:9be122c18509 1818 if( Rx2Channel.Datarate >= DR_3 )
GregCr 0:9be122c18509 1819 { // DR_6, DR_5, DR_4, DR_3
Alliance 5:50aab2960e8c 1820 symbTimeout = 80;
GregCr 0:9be122c18509 1821 }
GregCr 0:9be122c18509 1822 if( Rx2Channel.Datarate == DR_6 )
GregCr 0:9be122c18509 1823 {// LoRa 250 kHz
GregCr 0:9be122c18509 1824 bandwidth = 1;
GregCr 0:9be122c18509 1825 }
GregCr 0:9be122c18509 1826
GregCr 0:9be122c18509 1827 LoRaMacEventFlags.Bits.RxSlot = 1;
GregCr 0:9be122c18509 1828 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1829 {
GregCr 0:9be122c18509 1830 LoRaMacRxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, false );
GregCr 0:9be122c18509 1831 }
GregCr 0:9be122c18509 1832 else
GregCr 0:9be122c18509 1833 {
GregCr 0:9be122c18509 1834 LoRaMacRxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, true );
GregCr 0:9be122c18509 1835 }
GregCr 0:9be122c18509 1836 }
GregCr 0:9be122c18509 1837
GregCr 0:9be122c18509 1838 /*!
GregCr 0:9be122c18509 1839 * Function executed on MacStateCheck timer event
GregCr 0:9be122c18509 1840 */
GregCr 0:9be122c18509 1841 static void OnMacStateCheckTimerEvent( void )
GregCr 0:9be122c18509 1842 {
GregCr 1:0a272b37c6cd 1843 MacStateCheckTimer.detach( );
GregCr 0:9be122c18509 1844
GregCr 0:9be122c18509 1845 if( LoRaMacEventFlags.Bits.Tx == 1 )
GregCr 0:9be122c18509 1846 {
GregCr 0:9be122c18509 1847 if( NodeAckRequested == false )
GregCr 0:9be122c18509 1848 {
GregCr 0:9be122c18509 1849 if( LoRaMacEventFlags.Bits.JoinAccept == true )
GregCr 0:9be122c18509 1850 {
GregCr 0:9be122c18509 1851 // Join messages aren't repeated automatically
GregCr 0:9be122c18509 1852 ChannelsNbRepCounter = ChannelsNbRep;
GregCr 0:9be122c18509 1853 UpLinkCounter = 0;
GregCr 0:9be122c18509 1854 }
GregCr 0:9be122c18509 1855 if( ChannelsNbRepCounter >= ChannelsNbRep )
GregCr 0:9be122c18509 1856 {
GregCr 0:9be122c18509 1857 ChannelsNbRepCounter = 0;
GregCr 0:9be122c18509 1858
GregCr 0:9be122c18509 1859 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1860
GregCr 0:9be122c18509 1861 AdrAckCounter++;
GregCr 0:9be122c18509 1862 if( IsUpLinkCounterFixed == false )
GregCr 0:9be122c18509 1863 {
GregCr 0:9be122c18509 1864 UpLinkCounter++;
GregCr 0:9be122c18509 1865 }
GregCr 0:9be122c18509 1866
GregCr 0:9be122c18509 1867 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1868 }
GregCr 0:9be122c18509 1869 else
GregCr 0:9be122c18509 1870 {
GregCr 0:9be122c18509 1871 LoRaMacEventFlags.Bits.Tx = 0;
GregCr 0:9be122c18509 1872 // Sends the same frame again
GregCr 0:9be122c18509 1873 if( LoRaMacSetNextChannel( ) == 0 )
GregCr 0:9be122c18509 1874 {
GregCr 0:9be122c18509 1875 LoRaMacSendFrameOnChannel( Channels[Channel] );
GregCr 0:9be122c18509 1876 }
GregCr 0:9be122c18509 1877 }
GregCr 0:9be122c18509 1878 }
GregCr 0:9be122c18509 1879
GregCr 0:9be122c18509 1880 if( LoRaMacEventFlags.Bits.Rx == 1 )
GregCr 0:9be122c18509 1881 {
GregCr 0:9be122c18509 1882 if( ( LoRaMacEventInfo.TxAckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) )
GregCr 0:9be122c18509 1883 {
GregCr 0:9be122c18509 1884 AckTimeoutRetry = false;
GregCr 0:9be122c18509 1885 if( IsUpLinkCounterFixed == false )
GregCr 0:9be122c18509 1886 {
GregCr 0:9be122c18509 1887 UpLinkCounter++;
GregCr 0:9be122c18509 1888 }
GregCr 0:9be122c18509 1889 LoRaMacEventInfo.TxNbRetries = AckTimeoutRetriesCounter;
GregCr 0:9be122c18509 1890
GregCr 0:9be122c18509 1891 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1892 }
GregCr 0:9be122c18509 1893 }
GregCr 0:9be122c18509 1894
GregCr 0:9be122c18509 1895 if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & MAC_CHANNEL_CHECK ) == 0 ) )
GregCr 0:9be122c18509 1896 {
GregCr 0:9be122c18509 1897 AckTimeoutRetry = false;
GregCr 0:9be122c18509 1898 if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) )
GregCr 0:9be122c18509 1899 {
GregCr 0:9be122c18509 1900 AckTimeoutRetriesCounter++;
GregCr 0:9be122c18509 1901
GregCr 0:9be122c18509 1902 if( ( AckTimeoutRetriesCounter % 2 ) == 1 )
GregCr 0:9be122c18509 1903 {
GregCr 0:9be122c18509 1904 ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_MIN_DATARATE );
GregCr 0:9be122c18509 1905 }
GregCr 0:9be122c18509 1906 LoRaMacEventFlags.Bits.Tx = 0;
GregCr 0:9be122c18509 1907 // Sends the same frame again
GregCr 0:9be122c18509 1908 if( LoRaMacSetNextChannel( ) == 0 )
GregCr 0:9be122c18509 1909 {
GregCr 0:9be122c18509 1910 LoRaMacSendFrameOnChannel( Channels[Channel] );
GregCr 0:9be122c18509 1911 }
GregCr 0:9be122c18509 1912 }
GregCr 0:9be122c18509 1913 else
GregCr 0:9be122c18509 1914 {
GregCr 0:9be122c18509 1915 // Re-enable default channels LC1, LC2, LC3
GregCr 0:9be122c18509 1916 ChannelsMask = ChannelsMask | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
GregCr 0:9be122c18509 1917
GregCr 0:9be122c18509 1918 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1919
GregCr 0:9be122c18509 1920 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 1921 LoRaMacEventInfo.TxNbRetries = AckTimeoutRetriesCounter;
GregCr 0:9be122c18509 1922 if( IsUpLinkCounterFixed == false )
GregCr 0:9be122c18509 1923 {
GregCr 0:9be122c18509 1924 UpLinkCounter++;
GregCr 0:9be122c18509 1925 }
GregCr 0:9be122c18509 1926 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1927 }
GregCr 0:9be122c18509 1928 }
GregCr 0:9be122c18509 1929 }
GregCr 0:9be122c18509 1930 // Handle reception for Class B and Class C
GregCr 0:9be122c18509 1931 if( ( LoRaMacState & MAC_RX ) == MAC_RX )
GregCr 0:9be122c18509 1932 {
GregCr 0:9be122c18509 1933 LoRaMacState &= ~MAC_RX;
GregCr 0:9be122c18509 1934 }
GregCr 0:9be122c18509 1935 if( LoRaMacState == MAC_IDLE )
GregCr 0:9be122c18509 1936 {
GregCr 0:9be122c18509 1937 LoRaMacNotify( &LoRaMacEventFlags, &LoRaMacEventInfo );
GregCr 0:9be122c18509 1938 }
GregCr 0:9be122c18509 1939 else
GregCr 0:9be122c18509 1940 {
GregCr 0:9be122c18509 1941 // Operation not finished restart timer
GregCr 0:9be122c18509 1942 MacStateCheckTimer.attach_us( &OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT );
GregCr 0:9be122c18509 1943 }
GregCr 0:9be122c18509 1944 }
GregCr 0:9be122c18509 1945
GregCr 0:9be122c18509 1946 static void OnAckTimeoutTimerEvent( void )
GregCr 0:9be122c18509 1947 {
GregCr 1:0a272b37c6cd 1948 AckTimeoutTimer.detach( );
GregCr 0:9be122c18509 1949
GregCr 0:9be122c18509 1950 AckTimeoutRetry = true;
GregCr 0:9be122c18509 1951 LoRaMacState &= ~MAC_ACK_REQ;
GregCr 0:9be122c18509 1952 }
GregCr 0:9be122c18509 1953
GregCr 0:9be122c18509 1954 /*!
GregCr 0:9be122c18509 1955 * ============================================================================
GregCr 0:9be122c18509 1956 * = LoRaMac test functions =
GregCr 0:9be122c18509 1957 * ============================================================================
GregCr 0:9be122c18509 1958 */
GregCr 0:9be122c18509 1959
GregCr 0:9be122c18509 1960 void LoRaMacSetDeviceClass( DeviceClass_t deviceClass )
GregCr 0:9be122c18509 1961 {
GregCr 0:9be122c18509 1962 LoRaMacDeviceClass = deviceClass;
GregCr 0:9be122c18509 1963 }
GregCr 0:9be122c18509 1964
GregCr 0:9be122c18509 1965 void LoRaMacSetPublicNetwork( bool enable )
GregCr 0:9be122c18509 1966 {
GregCr 0:9be122c18509 1967 PublicNetwork = enable;
GregCr 0:9be122c18509 1968 Radio.SetModem( MODEM_LORA );
GregCr 0:9be122c18509 1969 if( PublicNetwork == true )
GregCr 0:9be122c18509 1970 {
GregCr 0:9be122c18509 1971 // Change LoRa modem SyncWord
GregCr 0:9be122c18509 1972 Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD );
GregCr 0:9be122c18509 1973 }
GregCr 0:9be122c18509 1974 else
GregCr 0:9be122c18509 1975 {
GregCr 0:9be122c18509 1976 // Change LoRa modem SyncWord
GregCr 0:9be122c18509 1977 Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD );
GregCr 0:9be122c18509 1978 }
GregCr 0:9be122c18509 1979 }
GregCr 0:9be122c18509 1980
GregCr 0:9be122c18509 1981 void LoRaMacSetDutyCycleOn( bool enable )
GregCr 0:9be122c18509 1982 {
GregCr 0:9be122c18509 1983 DutyCycleOn = enable;
GregCr 0:9be122c18509 1984 }
GregCr 0:9be122c18509 1985
GregCr 0:9be122c18509 1986 void LoRaMacSetChannel( uint8_t id, ChannelParams_t params )
GregCr 0:9be122c18509 1987 {
GregCr 0:9be122c18509 1988 params.Band = 0;
GregCr 0:9be122c18509 1989 Channels[id] = params;
GregCr 0:9be122c18509 1990 // Activate the newly created channel
GregCr 0:9be122c18509 1991 ChannelsMask |= 1 << id;
GregCr 0:9be122c18509 1992
GregCr 0:9be122c18509 1993 #if defined( USE_BAND_868 )
GregCr 0:9be122c18509 1994 if( ( Channels[id].Frequency >= 865000000 ) && ( Channels[id].Frequency <= 868000000 ) )
GregCr 0:9be122c18509 1995 {
GregCr 0:9be122c18509 1996 if( Channels[id].Band != BAND_G1_0 )
GregCr 0:9be122c18509 1997 {
GregCr 0:9be122c18509 1998 Channels[id].Band = BAND_G1_0;
GregCr 0:9be122c18509 1999 }
GregCr 0:9be122c18509 2000 }
GregCr 0:9be122c18509 2001 else if( ( Channels[id].Frequency > 868000000 ) && ( Channels[id].Frequency <= 868600000 ) )
GregCr 0:9be122c18509 2002 {
GregCr 0:9be122c18509 2003 if( Channels[id].Band != BAND_G1_1 )
GregCr 0:9be122c18509 2004 {
GregCr 0:9be122c18509 2005 Channels[id].Band = BAND_G1_1;
GregCr 0:9be122c18509 2006 }
GregCr 0:9be122c18509 2007 }
GregCr 0:9be122c18509 2008 else if( ( Channels[id].Frequency >= 868700000 ) && ( Channels[id].Frequency <= 869200000 ) )
GregCr 0:9be122c18509 2009 {
GregCr 0:9be122c18509 2010 if( Channels[id].Band != BAND_G1_2 )
GregCr 0:9be122c18509 2011 {
GregCr 0:9be122c18509 2012 Channels[id].Band = BAND_G1_2;
GregCr 0:9be122c18509 2013 }
GregCr 0:9be122c18509 2014 }
GregCr 0:9be122c18509 2015 else if( ( Channels[id].Frequency >= 869400000 ) && ( Channels[id].Frequency <= 869650000 ) )
GregCr 0:9be122c18509 2016 {
GregCr 0:9be122c18509 2017 if( Channels[id].Band != BAND_G1_3 )
GregCr 0:9be122c18509 2018 {
GregCr 0:9be122c18509 2019 Channels[id].Band = BAND_G1_3;
GregCr 0:9be122c18509 2020 }
GregCr 0:9be122c18509 2021 }
GregCr 0:9be122c18509 2022 else if( ( Channels[id].Frequency >= 869700000 ) && ( Channels[id].Frequency <= 870000000 ) )
GregCr 0:9be122c18509 2023 {
GregCr 0:9be122c18509 2024 if( Channels[id].Band != BAND_G1_4 )
GregCr 0:9be122c18509 2025 {
GregCr 0:9be122c18509 2026 Channels[id].Band = BAND_G1_4;
GregCr 0:9be122c18509 2027 }
GregCr 0:9be122c18509 2028 }
GregCr 0:9be122c18509 2029 else
GregCr 0:9be122c18509 2030 {
GregCr 0:9be122c18509 2031 Channels[id].Frequency = 0;
GregCr 0:9be122c18509 2032 Channels[id].DrRange.Value = 0;
GregCr 0:9be122c18509 2033 }
GregCr 0:9be122c18509 2034 #endif
GregCr 0:9be122c18509 2035 // Check if it is a valid channel
GregCr 0:9be122c18509 2036 if( Channels[id].Frequency == 0 )
GregCr 0:9be122c18509 2037 {
GregCr 0:9be122c18509 2038 ChannelsMask &= ~( 1 << id );
GregCr 0:9be122c18509 2039 }
GregCr 0:9be122c18509 2040 }
GregCr 0:9be122c18509 2041
GregCr 0:9be122c18509 2042 void LoRaMacSetRx2Channel( Rx2ChannelParams_t param )
GregCr 0:9be122c18509 2043 {
GregCr 0:9be122c18509 2044 Rx2Channel = param;
GregCr 0:9be122c18509 2045 }
GregCr 0:9be122c18509 2046
GregCr 0:9be122c18509 2047 void LoRaMacSetChannelsTxPower( int8_t txPower )
GregCr 0:9be122c18509 2048 {
GregCr 0:9be122c18509 2049 ChannelsTxPower = txPower;
GregCr 0:9be122c18509 2050 }
GregCr 0:9be122c18509 2051
GregCr 0:9be122c18509 2052 void LoRaMacSetChannelsDatarate( int8_t datarate )
GregCr 0:9be122c18509 2053 {
GregCr 0:9be122c18509 2054 ChannelsDefaultDatarate = ChannelsDatarate = datarate;
GregCr 0:9be122c18509 2055 }
GregCr 0:9be122c18509 2056
GregCr 0:9be122c18509 2057 void LoRaMacSetChannelsMask( uint16_t mask )
GregCr 0:9be122c18509 2058 {
GregCr 0:9be122c18509 2059 ChannelsMask = mask;
GregCr 0:9be122c18509 2060 }
GregCr 0:9be122c18509 2061
GregCr 0:9be122c18509 2062 void LoRaMacSetChannelsNbRep( uint8_t nbRep )
GregCr 0:9be122c18509 2063 {
GregCr 0:9be122c18509 2064 if( nbRep < 1 )
GregCr 0:9be122c18509 2065 {
GregCr 0:9be122c18509 2066 nbRep = 1;
GregCr 0:9be122c18509 2067 }
GregCr 0:9be122c18509 2068 if( nbRep > 15 )
GregCr 0:9be122c18509 2069 {
GregCr 0:9be122c18509 2070 nbRep = 15;
GregCr 0:9be122c18509 2071 }
GregCr 0:9be122c18509 2072 ChannelsNbRep = nbRep;
GregCr 0:9be122c18509 2073 }
GregCr 0:9be122c18509 2074
GregCr 0:9be122c18509 2075 void LoRaMacSetMaxRxWindow( uint32_t delay )
GregCr 0:9be122c18509 2076 {
GregCr 0:9be122c18509 2077 MaxRxWindow = delay;
GregCr 0:9be122c18509 2078 }
GregCr 0:9be122c18509 2079
GregCr 0:9be122c18509 2080 void LoRaMacSetReceiveDelay1( uint32_t delay )
GregCr 0:9be122c18509 2081 {
GregCr 0:9be122c18509 2082 ReceiveDelay1 = delay;
GregCr 0:9be122c18509 2083 }
GregCr 0:9be122c18509 2084
GregCr 0:9be122c18509 2085 void LoRaMacSetReceiveDelay2( uint32_t delay )
GregCr 0:9be122c18509 2086 {
GregCr 0:9be122c18509 2087 ReceiveDelay2 = delay;
GregCr 0:9be122c18509 2088 }
GregCr 0:9be122c18509 2089
GregCr 0:9be122c18509 2090 void LoRaMacSetJoinAcceptDelay1( uint32_t delay )
GregCr 0:9be122c18509 2091 {
GregCr 0:9be122c18509 2092 JoinAcceptDelay1 = delay;
GregCr 0:9be122c18509 2093 }
GregCr 0:9be122c18509 2094
GregCr 0:9be122c18509 2095 void LoRaMacSetJoinAcceptDelay2( uint32_t delay )
GregCr 0:9be122c18509 2096 {
GregCr 0:9be122c18509 2097 JoinAcceptDelay2 = delay;
GregCr 0:9be122c18509 2098 }
GregCr 0:9be122c18509 2099
GregCr 0:9be122c18509 2100 void LoRaMacTestRxWindowsOn( bool enable )
GregCr 0:9be122c18509 2101 {
GregCr 0:9be122c18509 2102 IsRxWindowsEnabled = enable;
GregCr 0:9be122c18509 2103 }
GregCr 0:9be122c18509 2104
GregCr 0:9be122c18509 2105 uint32_t LoRaMacGetUpLinkCounter( void )
GregCr 0:9be122c18509 2106 {
GregCr 0:9be122c18509 2107 return UpLinkCounter;
GregCr 0:9be122c18509 2108 }
GregCr 0:9be122c18509 2109
GregCr 0:9be122c18509 2110 uint32_t LoRaMacGetDownLinkCounter( void )
GregCr 0:9be122c18509 2111 {
GregCr 0:9be122c18509 2112 return DownLinkCounter;
GregCr 0:9be122c18509 2113 }
GregCr 0:9be122c18509 2114
GregCr 0:9be122c18509 2115 void LoRaMacSetMicTest( uint16_t upLinkCounter )
GregCr 0:9be122c18509 2116 {
GregCr 0:9be122c18509 2117 UpLinkCounter = upLinkCounter;
GregCr 0:9be122c18509 2118 IsUpLinkCounterFixed = true;
GregCr 0:9be122c18509 2119 }