this is avaiable project

Dependents:   LoRaWAN_MBED

Fork of LoRaMacLib by LoRa All

Committer:
GregCr
Date:
Mon Sep 21 07:54:54 2015 +0000
Revision:
3:675d14219ad5
Parent:
2:737ad7fbc97e
Child:
4:c1d2d1319c8f
Increased Rx Window size

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,
GregCr 0:9be122c18509 206 LC7,
GregCr 0:9be122c18509 207 LC8,
GregCr 0:9be122c18509 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
GregCr 0:9be122c18509 836 macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
GregCr 0:9be122c18509 837 return LoRaMacSend( &macHdr, NULL, fPort, fBuffer, fBufferSize );
GregCr 0:9be122c18509 838 }
GregCr 0:9be122c18509 839
GregCr 0:9be122c18509 840 uint8_t LoRaMacSendConfirmedFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize, uint8_t retries )
GregCr 0:9be122c18509 841 {
GregCr 0:9be122c18509 842 LoRaMacHeader_t macHdr;
GregCr 0:9be122c18509 843
GregCr 0:9be122c18509 844 if( AdrCtrlOn == false )
GregCr 0:9be122c18509 845 {
GregCr 0:9be122c18509 846 ChannelsDatarate = ChannelsDefaultDatarate;
GregCr 0:9be122c18509 847 }
GregCr 0:9be122c18509 848 AckTimeoutRetries = retries;
GregCr 0:9be122c18509 849 AckTimeoutRetriesCounter = 1;
GregCr 0:9be122c18509 850
GregCr 0:9be122c18509 851 macHdr.Value = 0;
GregCr 0:9be122c18509 852
GregCr 0:9be122c18509 853 macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
GregCr 0:9be122c18509 854 return LoRaMacSend( &macHdr, NULL, fPort, fBuffer, fBufferSize );
GregCr 0:9be122c18509 855 }
GregCr 0:9be122c18509 856
GregCr 0:9be122c18509 857 uint8_t LoRaMacSend( LoRaMacHeader_t *macHdr, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
GregCr 0:9be122c18509 858 {
GregCr 0:9be122c18509 859 LoRaMacFrameCtrl_t fCtrl;
GregCr 0:9be122c18509 860
GregCr 0:9be122c18509 861 fCtrl.Value = 0;
GregCr 0:9be122c18509 862
GregCr 0:9be122c18509 863 fCtrl.Bits.FOptsLen = 0;
GregCr 0:9be122c18509 864 fCtrl.Bits.FPending = 0;
GregCr 0:9be122c18509 865 fCtrl.Bits.Ack = false;
GregCr 0:9be122c18509 866 fCtrl.Bits.AdrAckReq = false;
GregCr 0:9be122c18509 867 fCtrl.Bits.Adr = AdrCtrlOn;
GregCr 0:9be122c18509 868
GregCr 0:9be122c18509 869 if( LoRaMacSetNextChannel( ) == 0 )
GregCr 0:9be122c18509 870 {
GregCr 0:9be122c18509 871 return LoRaMacSendOnChannel( Channels[Channel], macHdr, &fCtrl, fOpts, fPort, fBuffer, fBufferSize );
GregCr 0:9be122c18509 872 }
GregCr 0:9be122c18509 873 return 5;
GregCr 0:9be122c18509 874 }
GregCr 0:9be122c18509 875
GregCr 0:9be122c18509 876 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 877 {
GregCr 0:9be122c18509 878 uint16_t i;
GregCr 0:9be122c18509 879 uint8_t pktHeaderLen = 0;
GregCr 0:9be122c18509 880 uint32_t mic = 0;
GregCr 0:9be122c18509 881
GregCr 0:9be122c18509 882 LoRaMacBufferPktLen = 0;
GregCr 0:9be122c18509 883
GregCr 0:9be122c18509 884 NodeAckRequested = false;
GregCr 0:9be122c18509 885
GregCr 0:9be122c18509 886 if( fBuffer == NULL )
GregCr 0:9be122c18509 887 {
GregCr 0:9be122c18509 888 fBufferSize = 0;
GregCr 0:9be122c18509 889 }
GregCr 0:9be122c18509 890
GregCr 0:9be122c18509 891 LoRaMacBuffer[pktHeaderLen++] = macHdr->Value;
GregCr 0:9be122c18509 892
GregCr 0:9be122c18509 893 switch( macHdr->Bits.MType )
GregCr 0:9be122c18509 894 {
GregCr 0:9be122c18509 895 case FRAME_TYPE_JOIN_REQ:
GregCr 0:9be122c18509 896 RxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME;
GregCr 0:9be122c18509 897 RxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME;
GregCr 0:9be122c18509 898
GregCr 0:9be122c18509 899 LoRaMacBufferPktLen = pktHeaderLen;
GregCr 0:9be122c18509 900
GregCr 0:9be122c18509 901 LoRaMacMemCpy( LoRaMacAppEui, LoRaMacBuffer + LoRaMacBufferPktLen, 8 );
GregCr 0:9be122c18509 902 LoRaMacBufferPktLen += 8;
GregCr 0:9be122c18509 903 LoRaMacMemCpy( LoRaMacDevEui, LoRaMacBuffer + LoRaMacBufferPktLen, 8 );
GregCr 0:9be122c18509 904 LoRaMacBufferPktLen += 8;
GregCr 0:9be122c18509 905
GregCr 0:9be122c18509 906 LoRaMacDevNonce = Radio.Random( );
GregCr 0:9be122c18509 907
GregCr 0:9be122c18509 908 LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF;
GregCr 0:9be122c18509 909 LoRaMacBuffer[LoRaMacBufferPktLen++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
GregCr 0:9be122c18509 910
GregCr 0:9be122c18509 911 LoRaMacJoinComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic );
GregCr 0:9be122c18509 912
GregCr 0:9be122c18509 913 LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF;
GregCr 0:9be122c18509 914 LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 8 ) & 0xFF;
GregCr 0:9be122c18509 915 LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 16 ) & 0xFF;
GregCr 0:9be122c18509 916 LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 24 ) & 0xFF;
GregCr 0:9be122c18509 917
GregCr 0:9be122c18509 918 break;
GregCr 0:9be122c18509 919 case FRAME_TYPE_DATA_CONFIRMED_UP:
GregCr 0:9be122c18509 920 NodeAckRequested = true;
GregCr 0:9be122c18509 921 //Intentional falltrough
GregCr 0:9be122c18509 922 case FRAME_TYPE_DATA_UNCONFIRMED_UP:
GregCr 0:9be122c18509 923 if( IsLoRaMacNetworkJoined == false )
GregCr 0:9be122c18509 924 {
GregCr 0:9be122c18509 925 return 2; // No network has been joined yet
GregCr 0:9be122c18509 926 }
GregCr 0:9be122c18509 927
GregCr 0:9be122c18509 928 RxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME;
GregCr 0:9be122c18509 929 RxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME;
GregCr 0:9be122c18509 930
GregCr 0:9be122c18509 931 if( fOpts == NULL )
GregCr 0:9be122c18509 932 {
GregCr 0:9be122c18509 933 fCtrl->Bits.FOptsLen = 0;
GregCr 0:9be122c18509 934 }
GregCr 0:9be122c18509 935
GregCr 0:9be122c18509 936 if( SrvAckRequested == true )
GregCr 0:9be122c18509 937 {
GregCr 0:9be122c18509 938 SrvAckRequested = false;
GregCr 0:9be122c18509 939 fCtrl->Bits.Ack = 1;
GregCr 0:9be122c18509 940 }
GregCr 0:9be122c18509 941
GregCr 0:9be122c18509 942 if( fCtrl->Bits.Adr == true )
GregCr 0:9be122c18509 943 {
GregCr 0:9be122c18509 944 if( ChannelsDatarate == LORAMAC_MIN_DATARATE )
GregCr 0:9be122c18509 945 {
GregCr 0:9be122c18509 946 AdrAckCounter = 0;
GregCr 0:9be122c18509 947 fCtrl->Bits.AdrAckReq = false;
GregCr 0:9be122c18509 948 }
GregCr 0:9be122c18509 949 else
GregCr 0:9be122c18509 950 {
GregCr 0:9be122c18509 951 if( AdrAckCounter > ADR_ACK_LIMIT )
GregCr 0:9be122c18509 952 {
GregCr 0:9be122c18509 953 fCtrl->Bits.AdrAckReq = true;
GregCr 0:9be122c18509 954 }
GregCr 0:9be122c18509 955 else
GregCr 0:9be122c18509 956 {
GregCr 0:9be122c18509 957 fCtrl->Bits.AdrAckReq = false;
GregCr 0:9be122c18509 958 }
GregCr 0:9be122c18509 959 if( AdrAckCounter > ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) )
GregCr 0:9be122c18509 960 {
GregCr 0:9be122c18509 961 AdrAckCounter = 0;
GregCr 0:9be122c18509 962 if( ChannelsDatarate > LORAMAC_MIN_DATARATE )
GregCr 0:9be122c18509 963 {
GregCr 0:9be122c18509 964 ChannelsDatarate--;
GregCr 0:9be122c18509 965 }
GregCr 0:9be122c18509 966 else
GregCr 0:9be122c18509 967 {
GregCr 0:9be122c18509 968 // Re-enable default channels LC1, LC2, LC3
GregCr 0:9be122c18509 969 ChannelsMask = ChannelsMask | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
GregCr 0:9be122c18509 970 }
GregCr 0:9be122c18509 971 }
GregCr 0:9be122c18509 972 }
GregCr 0:9be122c18509 973 }
GregCr 0:9be122c18509 974
GregCr 0:9be122c18509 975 LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF;
GregCr 0:9be122c18509 976 LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
GregCr 0:9be122c18509 977 LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
GregCr 0:9be122c18509 978 LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
GregCr 0:9be122c18509 979
GregCr 0:9be122c18509 980 LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value;
GregCr 0:9be122c18509 981
GregCr 0:9be122c18509 982 LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF;
GregCr 0:9be122c18509 983 LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF;
GregCr 0:9be122c18509 984
GregCr 0:9be122c18509 985 if( fOpts != NULL )
GregCr 0:9be122c18509 986 {
GregCr 0:9be122c18509 987 for( i = 0; i < fCtrl->Bits.FOptsLen; i++ )
GregCr 0:9be122c18509 988 {
GregCr 0:9be122c18509 989 LoRaMacBuffer[pktHeaderLen++] = fOpts[i];
GregCr 0:9be122c18509 990 }
GregCr 0:9be122c18509 991 }
GregCr 0:9be122c18509 992 if( ( MacCommandsBufferIndex + fCtrl->Bits.FOptsLen ) <= 15 )
GregCr 0:9be122c18509 993 {
GregCr 0:9be122c18509 994 if( MacCommandsInNextTx == true )
GregCr 0:9be122c18509 995 {
GregCr 0:9be122c18509 996 fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
GregCr 0:9be122c18509 997
GregCr 0:9be122c18509 998 // Update FCtrl field with new value of OptionsLength
GregCr 0:9be122c18509 999 LoRaMacBuffer[0x05] = fCtrl->Value;
GregCr 0:9be122c18509 1000 for( i = 0; i < MacCommandsBufferIndex; i++ )
GregCr 0:9be122c18509 1001 {
GregCr 0:9be122c18509 1002 LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
GregCr 0:9be122c18509 1003 }
GregCr 0:9be122c18509 1004 }
GregCr 0:9be122c18509 1005 MacCommandsInNextTx = false;
GregCr 0:9be122c18509 1006 MacCommandsBufferIndex = 0;
GregCr 0:9be122c18509 1007 }
GregCr 0:9be122c18509 1008
GregCr 0:9be122c18509 1009 if( ( pktHeaderLen + fBufferSize ) > LORAMAC_PHY_MAXPAYLOAD )
GregCr 0:9be122c18509 1010 {
GregCr 0:9be122c18509 1011 return 3;
GregCr 0:9be122c18509 1012 }
GregCr 0:9be122c18509 1013
GregCr 0:9be122c18509 1014 if( fBuffer != NULL )
GregCr 0:9be122c18509 1015 {
GregCr 0:9be122c18509 1016 LoRaMacBuffer[pktHeaderLen] = fPort;
GregCr 0:9be122c18509 1017
GregCr 0:9be122c18509 1018 if( fPort == 0 )
GregCr 0:9be122c18509 1019 {
GregCr 0:9be122c18509 1020 LoRaMacPayloadEncrypt( (uint8_t*)fBuffer, fBufferSize, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
GregCr 0:9be122c18509 1021 }
GregCr 0:9be122c18509 1022 else
GregCr 0:9be122c18509 1023 {
GregCr 0:9be122c18509 1024 LoRaMacPayloadEncrypt( (uint8_t*)fBuffer, fBufferSize, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
GregCr 0:9be122c18509 1025 }
GregCr 0:9be122c18509 1026 LoRaMacMemCpy( LoRaMacPayload, LoRaMacBuffer + pktHeaderLen + 1, fBufferSize );
GregCr 0:9be122c18509 1027 }
GregCr 0:9be122c18509 1028 LoRaMacBufferPktLen = pktHeaderLen + 1 + fBufferSize;
GregCr 0:9be122c18509 1029
GregCr 0:9be122c18509 1030 LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic );
GregCr 0:9be122c18509 1031
GregCr 0:9be122c18509 1032 if( ( LoRaMacBufferPktLen + LORAMAC_MFR_LEN ) > LORAMAC_PHY_MAXPAYLOAD )
GregCr 0:9be122c18509 1033 {
GregCr 0:9be122c18509 1034 return 3;
GregCr 0:9be122c18509 1035 }
GregCr 0:9be122c18509 1036 LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF;
GregCr 0:9be122c18509 1037 LoRaMacBuffer[LoRaMacBufferPktLen + 1] = ( mic >> 8 ) & 0xFF;
GregCr 0:9be122c18509 1038 LoRaMacBuffer[LoRaMacBufferPktLen + 2] = ( mic >> 16 ) & 0xFF;
GregCr 0:9be122c18509 1039 LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF;
GregCr 0:9be122c18509 1040
GregCr 0:9be122c18509 1041 LoRaMacBufferPktLen += LORAMAC_MFR_LEN;
GregCr 0:9be122c18509 1042 break;
GregCr 0:9be122c18509 1043 default:
GregCr 0:9be122c18509 1044 return 4;
GregCr 0:9be122c18509 1045 }
GregCr 0:9be122c18509 1046
GregCr 0:9be122c18509 1047 return 0;
GregCr 0:9be122c18509 1048 }
GregCr 0:9be122c18509 1049
GregCr 0:9be122c18509 1050 uint8_t LoRaMacSendFrameOnChannel( ChannelParams_t channel )
GregCr 0:9be122c18509 1051 {
GregCr 0:9be122c18509 1052 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
GregCr 0:9be122c18509 1053 LoRaMacEventInfo.TxDatarate = Datarates[ChannelsDatarate];
GregCr 0:9be122c18509 1054
GregCr 0:9be122c18509 1055 Radio.SetChannel( channel.Frequency );
GregCr 0:9be122c18509 1056
GregCr 0:9be122c18509 1057 if( ChannelsDatarate == DR_7 )
GregCr 0:9be122c18509 1058 { // High Speed FSK channel
GregCr 0:9be122c18509 1059 Radio.SetTxConfig( MODEM_FSK, TxPowers[ChannelsTxPower], 25e3, 0, Datarates[ChannelsDatarate] * 1e3, 0, 5, false, true, 0, 0, false, 3e6 );
GregCr 0:9be122c18509 1060 TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1061 }
GregCr 0:9be122c18509 1062 else if( ChannelsDatarate == DR_6 )
GregCr 0:9be122c18509 1063 { // High speed LoRa channel
GregCr 0:9be122c18509 1064 Radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 1, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
GregCr 0:9be122c18509 1065 TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1066 }
GregCr 0:9be122c18509 1067 else
GregCr 0:9be122c18509 1068 { // Normal LoRa channel
GregCr 0:9be122c18509 1069 Radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 0, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
GregCr 0:9be122c18509 1070 TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1071 }
GregCr 0:9be122c18509 1072
GregCr 0:9be122c18509 1073 if( MaxDCycle == 255 )
GregCr 0:9be122c18509 1074 {
GregCr 0:9be122c18509 1075 return 6;
GregCr 0:9be122c18509 1076 }
GregCr 0:9be122c18509 1077 if( MaxDCycle == 0 )
GregCr 0:9be122c18509 1078 {
GregCr 0:9be122c18509 1079 AggregatedTimeOff = 0;
GregCr 0:9be122c18509 1080 }
GregCr 0:9be122c18509 1081
GregCr 0:9be122c18509 1082 LoRaMacState |= MAC_TX_RUNNING;
GregCr 0:9be122c18509 1083 // Starts the MAC layer status check timer
GregCr 0:9be122c18509 1084 MacStateCheckTimer.attach_us( &OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT );
GregCr 0:9be122c18509 1085
GregCr 0:9be122c18509 1086 if( MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) > ( TimerGetCurrentTime( ) ) )
GregCr 0:9be122c18509 1087 {
GregCr 0:9be122c18509 1088 // Schedule transmission
GregCr 0:9be122c18509 1089 TxDelayedTimer.attach_us( &OnTxDelayedTimerEvent, MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) );
GregCr 0:9be122c18509 1090 }
GregCr 0:9be122c18509 1091 else
GregCr 0:9be122c18509 1092 {
GregCr 0:9be122c18509 1093 // Send now
GregCr 0:9be122c18509 1094 Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1095 }
GregCr 0:9be122c18509 1096 return 0;
GregCr 0:9be122c18509 1097 }
GregCr 0:9be122c18509 1098
GregCr 0:9be122c18509 1099
GregCr 0:9be122c18509 1100 void OnTxDelayedTimerEvent( void )
GregCr 0:9be122c18509 1101 {
GregCr 2:737ad7fbc97e 1102 TxDelayedTimer.detach( );
GregCr 0:9be122c18509 1103 Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
GregCr 0:9be122c18509 1104 }
GregCr 0:9be122c18509 1105
GregCr 0:9be122c18509 1106 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 1107 {
GregCr 0:9be122c18509 1108 uint8_t status = 0;
GregCr 0:9be122c18509 1109
GregCr 0:9be122c18509 1110 if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
GregCr 0:9be122c18509 1111 {
GregCr 0:9be122c18509 1112 return 1; // MAC is busy transmitting a previous frame
GregCr 0:9be122c18509 1113 }
GregCr 0:9be122c18509 1114
GregCr 0:9be122c18509 1115 status = LoRaMacPrepareFrame( channel, macHdr, fCtrl, fOpts, fPort, fBuffer, fBufferSize );
GregCr 0:9be122c18509 1116 if( status != 0 )
GregCr 0:9be122c18509 1117 {
GregCr 0:9be122c18509 1118 return status;
GregCr 0:9be122c18509 1119 }
GregCr 0:9be122c18509 1120
GregCr 0:9be122c18509 1121 LoRaMacEventInfo.TxNbRetries = 0;
GregCr 0:9be122c18509 1122 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 1123
GregCr 0:9be122c18509 1124 return LoRaMacSendFrameOnChannel( channel );
GregCr 0:9be122c18509 1125 }
GregCr 0:9be122c18509 1126
GregCr 0:9be122c18509 1127 static void LoRaMacProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize )
GregCr 0:9be122c18509 1128 {
GregCr 0:9be122c18509 1129 while( macIndex < commandsSize )
GregCr 0:9be122c18509 1130 {
GregCr 0:9be122c18509 1131 // Decode Frame MAC commands
GregCr 0:9be122c18509 1132 switch( payload[macIndex++] )
GregCr 0:9be122c18509 1133 {
GregCr 0:9be122c18509 1134 case SRV_MAC_LINK_CHECK_ANS:
GregCr 0:9be122c18509 1135 LoRaMacEventFlags.Bits.LinkCheck = 1;
GregCr 0:9be122c18509 1136 LoRaMacEventInfo.DemodMargin = payload[macIndex++];
GregCr 0:9be122c18509 1137 LoRaMacEventInfo.NbGateways = payload[macIndex++];
GregCr 0:9be122c18509 1138 break;
GregCr 0:9be122c18509 1139 case SRV_MAC_LINK_ADR_REQ:
GregCr 0:9be122c18509 1140 {
GregCr 0:9be122c18509 1141 uint8_t i;
GregCr 0:9be122c18509 1142 uint8_t status = 0x07;
GregCr 0:9be122c18509 1143 uint16_t chMask = 0;
GregCr 0:9be122c18509 1144 int8_t txPower = 0;
GregCr 0:9be122c18509 1145 int8_t datarate = 0;
GregCr 0:9be122c18509 1146 uint8_t nbRep = 0;
GregCr 0:9be122c18509 1147 uint8_t chMaskCntl = 0;
GregCr 0:9be122c18509 1148
GregCr 0:9be122c18509 1149 datarate = payload[macIndex++];
GregCr 0:9be122c18509 1150 txPower = datarate & 0x0F;
GregCr 0:9be122c18509 1151 datarate = ( datarate >> 4 ) & 0x0F;
GregCr 0:9be122c18509 1152
GregCr 0:9be122c18509 1153 if( ( AdrCtrlOn == false ) &&
GregCr 0:9be122c18509 1154 ( ( ChannelsDatarate != datarate ) || ( ChannelsTxPower != txPower ) ) )
GregCr 0:9be122c18509 1155 { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower
GregCr 0:9be122c18509 1156 // Answer the server with fail status
GregCr 0:9be122c18509 1157 // Power ACK = 0
GregCr 0:9be122c18509 1158 // Data rate ACK = 0
GregCr 0:9be122c18509 1159 // Channel mask = 0
GregCr 0:9be122c18509 1160 AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
GregCr 0:9be122c18509 1161 break;
GregCr 0:9be122c18509 1162 }
GregCr 0:9be122c18509 1163 chMask = payload[macIndex++];
GregCr 0:9be122c18509 1164 chMask |= payload[macIndex++] << 8;
GregCr 0:9be122c18509 1165
GregCr 0:9be122c18509 1166 nbRep = payload[macIndex++];
GregCr 0:9be122c18509 1167 chMaskCntl = ( nbRep >> 4 ) & 0x07;
GregCr 0:9be122c18509 1168 nbRep &= 0x0F;
GregCr 0:9be122c18509 1169 if( nbRep == 0 )
GregCr 0:9be122c18509 1170 {
GregCr 0:9be122c18509 1171 nbRep = 1;
GregCr 0:9be122c18509 1172 }
GregCr 0:9be122c18509 1173 if( ( chMaskCntl == 0 ) && ( chMask == 0 ) )
GregCr 0:9be122c18509 1174 {
GregCr 0:9be122c18509 1175 status &= 0xFE; // Channel mask KO
GregCr 0:9be122c18509 1176 }
GregCr 0:9be122c18509 1177 else
GregCr 0:9be122c18509 1178 {
GregCr 0:9be122c18509 1179 for( i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
GregCr 0:9be122c18509 1180 {
GregCr 0:9be122c18509 1181 if( chMaskCntl == 6 )
GregCr 0:9be122c18509 1182 {
GregCr 0:9be122c18509 1183 if( Channels[i].Frequency != 0 )
GregCr 0:9be122c18509 1184 {
GregCr 0:9be122c18509 1185 chMask |= 1 << i;
GregCr 0:9be122c18509 1186 }
GregCr 0:9be122c18509 1187 }
GregCr 0:9be122c18509 1188 else
GregCr 0:9be122c18509 1189 {
GregCr 0:9be122c18509 1190 if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
GregCr 0:9be122c18509 1191 ( Channels[i].Frequency == 0 ) )
GregCr 0:9be122c18509 1192 {// Trying to enable an undefined channel
GregCr 0:9be122c18509 1193 status &= 0xFE; // Channel mask KO
GregCr 0:9be122c18509 1194 }
GregCr 0:9be122c18509 1195 }
GregCr 0:9be122c18509 1196 }
GregCr 0:9be122c18509 1197 }
GregCr 0:9be122c18509 1198 if( ( ( datarate < LORAMAC_MIN_DATARATE ) ||
GregCr 0:9be122c18509 1199 ( datarate > LORAMAC_MAX_DATARATE ) ) == true )
GregCr 0:9be122c18509 1200 {
GregCr 0:9be122c18509 1201 status &= 0xFD; // Datarate KO
GregCr 0:9be122c18509 1202 }
GregCr 0:9be122c18509 1203
GregCr 0:9be122c18509 1204 //
GregCr 0:9be122c18509 1205 // Remark MaxTxPower = 0 and MinTxPower = 5
GregCr 0:9be122c18509 1206 //
GregCr 0:9be122c18509 1207 if( ( ( LORAMAC_MAX_TX_POWER <= txPower ) &&
GregCr 0:9be122c18509 1208 ( txPower <= LORAMAC_MIN_TX_POWER ) ) == false )
GregCr 0:9be122c18509 1209 {
GregCr 0:9be122c18509 1210 status &= 0xFB; // TxPower KO
GregCr 0:9be122c18509 1211 }
GregCr 0:9be122c18509 1212 if( ( status & 0x07 ) == 0x07 )
GregCr 0:9be122c18509 1213 {
GregCr 0:9be122c18509 1214 ChannelsDatarate = datarate;
GregCr 0:9be122c18509 1215 ChannelsTxPower = txPower;
GregCr 0:9be122c18509 1216 ChannelsMask = chMask;
GregCr 0:9be122c18509 1217 ChannelsNbRep = nbRep;
GregCr 0:9be122c18509 1218 }
GregCr 0:9be122c18509 1219 AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );
GregCr 0:9be122c18509 1220 }
GregCr 0:9be122c18509 1221 break;
GregCr 0:9be122c18509 1222 case SRV_MAC_DUTY_CYCLE_REQ:
GregCr 0:9be122c18509 1223 MaxDCycle = payload[macIndex++];
GregCr 0:9be122c18509 1224 AggregatedDCycle = 1 << MaxDCycle;
GregCr 0:9be122c18509 1225 AddMacCommand( MOTE_MAC_DUTY_CYCLE_ANS, 0, 0 );
GregCr 0:9be122c18509 1226 break;
GregCr 0:9be122c18509 1227 case SRV_MAC_RX_PARAM_SETUP_REQ:
GregCr 0:9be122c18509 1228 {
GregCr 0:9be122c18509 1229 uint8_t status = 0x07;
GregCr 0:9be122c18509 1230 int8_t datarate = 0;
GregCr 0:9be122c18509 1231 int8_t drOffset = 0;
GregCr 0:9be122c18509 1232 uint32_t freq = 0;
GregCr 0:9be122c18509 1233
GregCr 0:9be122c18509 1234 drOffset = payload[macIndex++];
GregCr 0:9be122c18509 1235 datarate = drOffset & 0x0F;
GregCr 0:9be122c18509 1236 drOffset = ( drOffset >> 4 ) & 0x0F;
GregCr 0:9be122c18509 1237
GregCr 0:9be122c18509 1238 freq = payload[macIndex++];
GregCr 0:9be122c18509 1239 freq |= payload[macIndex++] << 8;
GregCr 0:9be122c18509 1240 freq |= payload[macIndex++] << 16;
GregCr 0:9be122c18509 1241 freq *= 100;
GregCr 0:9be122c18509 1242
GregCr 0:9be122c18509 1243 if( Radio.CheckRfFrequency( freq ) == false )
GregCr 0:9be122c18509 1244 {
GregCr 0:9be122c18509 1245 status &= 0xFE; // Channel frequency KO
GregCr 0:9be122c18509 1246 }
GregCr 0:9be122c18509 1247
GregCr 0:9be122c18509 1248 if( ( ( datarate < LORAMAC_MIN_DATARATE ) ||
GregCr 0:9be122c18509 1249 ( datarate > LORAMAC_MAX_DATARATE ) ) == true )
GregCr 0:9be122c18509 1250 {
GregCr 0:9be122c18509 1251 status &= 0xFD; // Datarate KO
GregCr 0:9be122c18509 1252 }
GregCr 0:9be122c18509 1253
GregCr 0:9be122c18509 1254 if( ( ( drOffset < 0 ) || ( drOffset > 5 ) ) == true )
GregCr 0:9be122c18509 1255 {
GregCr 0:9be122c18509 1256 status &= 0xFB; // Rx1DrOffset range KO
GregCr 0:9be122c18509 1257 }
GregCr 0:9be122c18509 1258
GregCr 0:9be122c18509 1259 if( ( status & 0x07 ) == 0x07 )
GregCr 0:9be122c18509 1260 {
GregCr 0:9be122c18509 1261 Rx2Channel.Datarate = datarate;
GregCr 0:9be122c18509 1262 Rx2Channel.Frequency = freq;
GregCr 0:9be122c18509 1263 Rx1DrOffset = drOffset;
GregCr 0:9be122c18509 1264 }
GregCr 0:9be122c18509 1265 AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 );
GregCr 0:9be122c18509 1266 }
GregCr 0:9be122c18509 1267 break;
GregCr 0:9be122c18509 1268 case SRV_MAC_DEV_STATUS_REQ:
GregCr 0:9be122c18509 1269 AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, BoardMeasureBatterieLevel( ), LoRaMacEventInfo.RxSnr );
GregCr 0:9be122c18509 1270 break;
GregCr 0:9be122c18509 1271 case SRV_MAC_NEW_CHANNEL_REQ:
GregCr 0:9be122c18509 1272 {
GregCr 0:9be122c18509 1273 uint8_t status = 0x03;
GregCr 0:9be122c18509 1274 int8_t channelIndex = 0;
GregCr 0:9be122c18509 1275 ChannelParams_t chParam;
GregCr 0:9be122c18509 1276
GregCr 0:9be122c18509 1277 channelIndex = payload[macIndex++];
GregCr 0:9be122c18509 1278 chParam.Frequency = payload[macIndex++];
GregCr 0:9be122c18509 1279 chParam.Frequency |= payload[macIndex++] << 8;
GregCr 0:9be122c18509 1280 chParam.Frequency |= payload[macIndex++] << 16;
GregCr 0:9be122c18509 1281 chParam.Frequency *= 100;
GregCr 0:9be122c18509 1282 chParam.DrRange.Value = payload[macIndex++];
GregCr 0:9be122c18509 1283
GregCr 0:9be122c18509 1284 if( ( channelIndex < 3 ) || ( channelIndex > LORA_MAX_NB_CHANNELS ) )
GregCr 0:9be122c18509 1285 {
GregCr 0:9be122c18509 1286 status &= 0xFE; // Channel frequency KO
GregCr 0:9be122c18509 1287 }
GregCr 0:9be122c18509 1288
GregCr 0:9be122c18509 1289 if( Radio.CheckRfFrequency( chParam.Frequency ) == false )
GregCr 0:9be122c18509 1290 {
GregCr 0:9be122c18509 1291 status &= 0xFE; // Channel frequency KO
GregCr 0:9be122c18509 1292 }
GregCr 0:9be122c18509 1293
GregCr 0:9be122c18509 1294 if( ( chParam.DrRange.Fields.Min > chParam.DrRange.Fields.Max ) ||
GregCr 0:9be122c18509 1295 ( ( ( LORAMAC_MIN_DATARATE <= chParam.DrRange.Fields.Min ) &&
GregCr 0:9be122c18509 1296 ( chParam.DrRange.Fields.Min <= LORAMAC_MAX_DATARATE ) ) == false ) ||
GregCr 0:9be122c18509 1297 ( ( ( LORAMAC_MIN_DATARATE <= chParam.DrRange.Fields.Max ) &&
GregCr 0:9be122c18509 1298 ( chParam.DrRange.Fields.Max <= LORAMAC_MAX_DATARATE ) ) == false ) )
GregCr 0:9be122c18509 1299 {
GregCr 0:9be122c18509 1300 status &= 0xFD; // Datarate range KO
GregCr 0:9be122c18509 1301 }
GregCr 0:9be122c18509 1302 if( ( status & 0x03 ) == 0x03 )
GregCr 0:9be122c18509 1303 {
GregCr 0:9be122c18509 1304 LoRaMacSetChannel( channelIndex, chParam );
GregCr 0:9be122c18509 1305 }
GregCr 0:9be122c18509 1306 AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
GregCr 0:9be122c18509 1307 }
GregCr 0:9be122c18509 1308 break;
GregCr 0:9be122c18509 1309 case SRV_MAC_RX_TIMING_SETUP_REQ:
GregCr 0:9be122c18509 1310 {
GregCr 0:9be122c18509 1311 uint8_t delay = payload[macIndex++] & 0x0F;
GregCr 0:9be122c18509 1312
GregCr 0:9be122c18509 1313 if( delay == 0 )
GregCr 0:9be122c18509 1314 {
GregCr 0:9be122c18509 1315 delay++;
GregCr 0:9be122c18509 1316 }
GregCr 0:9be122c18509 1317 ReceiveDelay1 = delay * 1e6;
GregCr 0:9be122c18509 1318 ReceiveDelay2 = ReceiveDelay1 + 1e6;
GregCr 0:9be122c18509 1319 AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
GregCr 0:9be122c18509 1320 }
GregCr 0:9be122c18509 1321 break;
GregCr 0:9be122c18509 1322 default:
GregCr 0:9be122c18509 1323 // Unknown command. ABORT MAC commands processing
GregCr 0:9be122c18509 1324 return;
GregCr 0:9be122c18509 1325 }
GregCr 0:9be122c18509 1326 }
GregCr 0:9be122c18509 1327 }
GregCr 0:9be122c18509 1328
GregCr 0:9be122c18509 1329 /*!
GregCr 0:9be122c18509 1330 * Function to be executed on Tx Done event
GregCr 0:9be122c18509 1331 */
GregCr 0:9be122c18509 1332 static void OnRadioTxDone( void )
GregCr 0:9be122c18509 1333 {
GregCr 0:9be122c18509 1334 uint64_t curTime = TimerGetCurrentTime( );
GregCr 0:9be122c18509 1335
GregCr 0:9be122c18509 1336 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1337 {
GregCr 0:9be122c18509 1338 Radio.Sleep( );
GregCr 0:9be122c18509 1339 }
GregCr 0:9be122c18509 1340 else
GregCr 0:9be122c18509 1341 {
GregCr 0:9be122c18509 1342 OnRxWindow2TimerEvent( );
GregCr 0:9be122c18509 1343 }
GregCr 0:9be122c18509 1344
GregCr 0:9be122c18509 1345 // Update Band Time OFF
GregCr 0:9be122c18509 1346 Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
GregCr 0:9be122c18509 1347 if( DutyCycleOn == true )
GregCr 0:9be122c18509 1348 {
GregCr 0:9be122c18509 1349 Bands[Channels[Channel].Band].TimeOff = TxTimeOnAir * Bands[Channels[Channel].Band].DCycle - TxTimeOnAir;
GregCr 0:9be122c18509 1350 }
GregCr 0:9be122c18509 1351 else
GregCr 0:9be122c18509 1352 {
GregCr 0:9be122c18509 1353 Bands[Channels[Channel].Band].TimeOff = 0;
GregCr 0:9be122c18509 1354 }
GregCr 0:9be122c18509 1355 // Update Agregated Time OFF
GregCr 0:9be122c18509 1356 AggregatedLastTxDoneTime = curTime;
GregCr 0:9be122c18509 1357 AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
GregCr 0:9be122c18509 1358
GregCr 0:9be122c18509 1359 if( IsRxWindowsEnabled == true )
GregCr 0:9be122c18509 1360 {
GregCr 0:9be122c18509 1361 RxWindowTimer1.attach_us( &OnRxWindow1TimerEvent, RxWindow1Delay );
GregCr 0:9be122c18509 1362
GregCr 0:9be122c18509 1363 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1364 {
GregCr 0:9be122c18509 1365 RxWindowTimer2.attach_us( &OnRxWindow2TimerEvent, RxWindow2Delay );
GregCr 0:9be122c18509 1366 }
GregCr 0:9be122c18509 1367 }
GregCr 0:9be122c18509 1368 else
GregCr 0:9be122c18509 1369 {
GregCr 0:9be122c18509 1370 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1371 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1372 }
GregCr 0:9be122c18509 1373
GregCr 0:9be122c18509 1374 if( NodeAckRequested == false )
GregCr 0:9be122c18509 1375 {
GregCr 0:9be122c18509 1376 ChannelsNbRepCounter++;
GregCr 0:9be122c18509 1377 }
GregCr 0:9be122c18509 1378 }
GregCr 0:9be122c18509 1379
GregCr 0:9be122c18509 1380 /*!
GregCr 0:9be122c18509 1381 * Function to be executed on Rx Done event
GregCr 0:9be122c18509 1382 */
GregCr 0:9be122c18509 1383 static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
GregCr 0:9be122c18509 1384 {
GregCr 0:9be122c18509 1385 LoRaMacHeader_t macHdr;
GregCr 0:9be122c18509 1386 LoRaMacFrameCtrl_t fCtrl;
GregCr 0:9be122c18509 1387
GregCr 0:9be122c18509 1388 uint8_t pktHeaderLen = 0;
GregCr 0:9be122c18509 1389 uint32_t address = 0;
GregCr 0:9be122c18509 1390 uint16_t sequenceCounter = 0;
GregCr 0:9be122c18509 1391 int32_t sequence = 0;
GregCr 0:9be122c18509 1392 uint8_t appPayloadStartIndex = 0;
GregCr 0:9be122c18509 1393 uint8_t port = 0xFF;
GregCr 0:9be122c18509 1394 uint8_t frameLen = 0;
GregCr 0:9be122c18509 1395 uint32_t mic = 0;
GregCr 0:9be122c18509 1396 uint32_t micRx = 0;
GregCr 0:9be122c18509 1397
GregCr 0:9be122c18509 1398 MulticastParams_t *curMulticastParams = NULL;
GregCr 0:9be122c18509 1399 uint8_t *nwkSKey = LoRaMacNwkSKey;
GregCr 0:9be122c18509 1400 uint8_t *appSKey = LoRaMacAppSKey;
GregCr 0:9be122c18509 1401 uint32_t downLinkCounter = 0;
GregCr 0:9be122c18509 1402
GregCr 0:9be122c18509 1403 bool isMicOk = false;
GregCr 0:9be122c18509 1404
GregCr 0:9be122c18509 1405 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1406 {
GregCr 0:9be122c18509 1407 Radio.Sleep( );
GregCr 0:9be122c18509 1408 }
GregCr 0:9be122c18509 1409 else
GregCr 0:9be122c18509 1410 {
GregCr 0:9be122c18509 1411 if( LoRaMacEventFlags.Bits.RxSlot == 0 )
GregCr 0:9be122c18509 1412 {
GregCr 0:9be122c18509 1413 OnRxWindow2TimerEvent( );
GregCr 0:9be122c18509 1414 }
GregCr 0:9be122c18509 1415 }
GregCr 2:737ad7fbc97e 1416 RxWindowTimer2.detach( ); // Timer is removed anyway in functions above
GregCr 0:9be122c18509 1417
GregCr 0:9be122c18509 1418 macHdr.Value = payload[pktHeaderLen++];
GregCr 0:9be122c18509 1419
GregCr 0:9be122c18509 1420 switch( macHdr.Bits.MType )
GregCr 0:9be122c18509 1421 {
GregCr 0:9be122c18509 1422 case FRAME_TYPE_JOIN_ACCEPT:
GregCr 0:9be122c18509 1423 if( IsLoRaMacNetworkJoined == true )
GregCr 0:9be122c18509 1424 {
GregCr 0:9be122c18509 1425 break;
GregCr 0:9be122c18509 1426 }
GregCr 0:9be122c18509 1427 LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 );
GregCr 0:9be122c18509 1428
GregCr 0:9be122c18509 1429 LoRaMacRxPayload[0] = macHdr.Value;
GregCr 0:9be122c18509 1430
GregCr 0:9be122c18509 1431 LoRaMacJoinComputeMic( LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic );
GregCr 0:9be122c18509 1432
GregCr 0:9be122c18509 1433 micRx |= LoRaMacRxPayload[size - LORAMAC_MFR_LEN];
GregCr 0:9be122c18509 1434 micRx |= ( LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8 );
GregCr 0:9be122c18509 1435 micRx |= ( LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 );
GregCr 0:9be122c18509 1436 micRx |= ( LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 );
GregCr 0:9be122c18509 1437
GregCr 0:9be122c18509 1438 if( micRx == mic )
GregCr 0:9be122c18509 1439 {
GregCr 0:9be122c18509 1440 LoRaMacEventFlags.Bits.Rx = 1;
GregCr 0:9be122c18509 1441 LoRaMacEventInfo.RxSnr = snr;
GregCr 0:9be122c18509 1442 LoRaMacEventInfo.RxRssi = rssi;
GregCr 0:9be122c18509 1443
GregCr 0:9be122c18509 1444 LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
GregCr 0:9be122c18509 1445
GregCr 0:9be122c18509 1446 LoRaMacNetID = LoRaMacRxPayload[4];
GregCr 0:9be122c18509 1447 LoRaMacNetID |= ( LoRaMacRxPayload[5] << 8 );
GregCr 0:9be122c18509 1448 LoRaMacNetID |= ( LoRaMacRxPayload[6] << 16 );
GregCr 0:9be122c18509 1449
GregCr 0:9be122c18509 1450 LoRaMacDevAddr = LoRaMacRxPayload[7];
GregCr 0:9be122c18509 1451 LoRaMacDevAddr |= ( LoRaMacRxPayload[8] << 8 );
GregCr 0:9be122c18509 1452 LoRaMacDevAddr |= ( LoRaMacRxPayload[9] << 16 );
GregCr 0:9be122c18509 1453 LoRaMacDevAddr |= ( LoRaMacRxPayload[10] << 24 );
GregCr 0:9be122c18509 1454
GregCr 0:9be122c18509 1455 // DLSettings
GregCr 0:9be122c18509 1456 Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07;
GregCr 0:9be122c18509 1457 Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
GregCr 0:9be122c18509 1458
GregCr 0:9be122c18509 1459 // RxDelay
GregCr 0:9be122c18509 1460 ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F );
GregCr 0:9be122c18509 1461 if( ReceiveDelay1 == 0 )
GregCr 0:9be122c18509 1462 {
GregCr 0:9be122c18509 1463 ReceiveDelay1 = 1;
GregCr 0:9be122c18509 1464 }
GregCr 0:9be122c18509 1465 ReceiveDelay1 *= 1e6;
GregCr 0:9be122c18509 1466 ReceiveDelay2 = ReceiveDelay1 + 1e6;
GregCr 0:9be122c18509 1467
GregCr 0:9be122c18509 1468 //CFList
GregCr 0:9be122c18509 1469 if( ( size - 1 ) > 16 )
GregCr 0:9be122c18509 1470 {
GregCr 0:9be122c18509 1471 ChannelParams_t param;
GregCr 0:9be122c18509 1472 param.DrRange.Value = ( DR_5 << 4 ) | DR_0;
GregCr 0:9be122c18509 1473
GregCr 0:9be122c18509 1474 for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 )
GregCr 0:9be122c18509 1475 {
GregCr 0:9be122c18509 1476 param.Frequency = ( LoRaMacRxPayload[13 + j] | ( LoRaMacRxPayload[14 + j] << 8 ) | ( LoRaMacRxPayload[15 + j] << 16 ) ) * 100;
GregCr 0:9be122c18509 1477 LoRaMacSetChannel( i, param );
GregCr 0:9be122c18509 1478 }
GregCr 0:9be122c18509 1479 }
GregCr 0:9be122c18509 1480
GregCr 0:9be122c18509 1481 LoRaMacEventFlags.Bits.JoinAccept = 1;
GregCr 0:9be122c18509 1482 IsLoRaMacNetworkJoined = true;
GregCr 0:9be122c18509 1483 ChannelsDatarate = ChannelsDefaultDatarate;
GregCr 0:9be122c18509 1484 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1485 }
GregCr 0:9be122c18509 1486 else
GregCr 0:9be122c18509 1487 {
GregCr 0:9be122c18509 1488 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
GregCr 0:9be122c18509 1489 }
GregCr 0:9be122c18509 1490
GregCr 0:9be122c18509 1491 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1492 break;
GregCr 0:9be122c18509 1493 case FRAME_TYPE_DATA_CONFIRMED_DOWN:
GregCr 0:9be122c18509 1494 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
GregCr 0:9be122c18509 1495 {
GregCr 0:9be122c18509 1496 address = payload[pktHeaderLen++];
GregCr 0:9be122c18509 1497 address |= ( payload[pktHeaderLen++] << 8 );
GregCr 0:9be122c18509 1498 address |= ( payload[pktHeaderLen++] << 16 );
GregCr 0:9be122c18509 1499 address |= ( payload[pktHeaderLen++] << 24 );
GregCr 0:9be122c18509 1500
GregCr 0:9be122c18509 1501 if( address != LoRaMacDevAddr )
GregCr 0:9be122c18509 1502 {
GregCr 0:9be122c18509 1503 curMulticastParams = MulticastChannels;
GregCr 0:9be122c18509 1504 while( curMulticastParams != NULL )
GregCr 0:9be122c18509 1505 {
GregCr 0:9be122c18509 1506 if( address == curMulticastParams->Address )
GregCr 0:9be122c18509 1507 {
GregCr 0:9be122c18509 1508 LoRaMacEventFlags.Bits.Multicast = 1;
GregCr 0:9be122c18509 1509 nwkSKey = curMulticastParams->NwkSKey;
GregCr 0:9be122c18509 1510 appSKey = curMulticastParams->AppSKey;
GregCr 0:9be122c18509 1511 downLinkCounter = curMulticastParams->DownLinkCounter;
GregCr 0:9be122c18509 1512 break;
GregCr 0:9be122c18509 1513 }
GregCr 0:9be122c18509 1514 curMulticastParams = curMulticastParams->Next;
GregCr 0:9be122c18509 1515 }
GregCr 0:9be122c18509 1516 if( LoRaMacEventFlags.Bits.Multicast == 0 )
GregCr 0:9be122c18509 1517 {
GregCr 0:9be122c18509 1518 // We are not the destination of this frame.
GregCr 0:9be122c18509 1519 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1520 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
GregCr 0:9be122c18509 1521 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1522 return;
GregCr 0:9be122c18509 1523 }
GregCr 0:9be122c18509 1524 }
GregCr 0:9be122c18509 1525 else
GregCr 0:9be122c18509 1526 {
GregCr 0:9be122c18509 1527 LoRaMacEventFlags.Bits.Multicast = 0;
GregCr 0:9be122c18509 1528 nwkSKey = LoRaMacNwkSKey;
GregCr 0:9be122c18509 1529 appSKey = LoRaMacAppSKey;
GregCr 0:9be122c18509 1530 downLinkCounter = DownLinkCounter;
GregCr 0:9be122c18509 1531 }
GregCr 0:9be122c18509 1532
GregCr 0:9be122c18509 1533 if( LoRaMacDeviceClass != CLASS_A )
GregCr 0:9be122c18509 1534 {
GregCr 0:9be122c18509 1535 LoRaMacState |= MAC_RX;
GregCr 0:9be122c18509 1536 // Starts the MAC layer status check timer
GregCr 0:9be122c18509 1537 MacStateCheckTimer.attach_us( &OnMacStateCheckTimerEvent , MAC_STATE_CHECK_TIMEOUT );
GregCr 0:9be122c18509 1538 }
GregCr 0:9be122c18509 1539 fCtrl.Value = payload[pktHeaderLen++];
GregCr 0:9be122c18509 1540
GregCr 0:9be122c18509 1541 sequenceCounter |= payload[pktHeaderLen++];
GregCr 0:9be122c18509 1542 sequenceCounter |= payload[pktHeaderLen++] << 8;
GregCr 0:9be122c18509 1543
GregCr 0:9be122c18509 1544 appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
GregCr 0:9be122c18509 1545
GregCr 0:9be122c18509 1546 micRx |= payload[size - LORAMAC_MFR_LEN];
GregCr 0:9be122c18509 1547 micRx |= ( payload[size - LORAMAC_MFR_LEN + 1] << 8 );
GregCr 0:9be122c18509 1548 micRx |= ( payload[size - LORAMAC_MFR_LEN + 2] << 16 );
GregCr 0:9be122c18509 1549 micRx |= ( payload[size - LORAMAC_MFR_LEN + 3] << 24 );
GregCr 0:9be122c18509 1550
GregCr 0:9be122c18509 1551 sequence = ( int32_t )sequenceCounter - ( int32_t )( downLinkCounter & 0xFFFF );
GregCr 0:9be122c18509 1552 if( sequence < 0 )
GregCr 0:9be122c18509 1553 {
GregCr 0:9be122c18509 1554 // sequence reset or roll over happened
GregCr 0:9be122c18509 1555 downLinkCounter = ( downLinkCounter & 0xFFFF0000 ) | ( sequenceCounter + ( uint32_t )0x10000 );
GregCr 0:9be122c18509 1556 LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
GregCr 0:9be122c18509 1557 if( micRx == mic )
GregCr 0:9be122c18509 1558 {
GregCr 0:9be122c18509 1559 isMicOk = true;
GregCr 0:9be122c18509 1560 }
GregCr 0:9be122c18509 1561 else
GregCr 0:9be122c18509 1562 {
GregCr 0:9be122c18509 1563 isMicOk = false;
GregCr 0:9be122c18509 1564 // sequence reset
GregCr 0:9be122c18509 1565 if( LoRaMacEventFlags.Bits.Multicast == 1 )
GregCr 0:9be122c18509 1566 {
GregCr 0:9be122c18509 1567 curMulticastParams->DownLinkCounter = downLinkCounter = sequenceCounter;
GregCr 0:9be122c18509 1568 }
GregCr 0:9be122c18509 1569 else
GregCr 0:9be122c18509 1570 {
GregCr 0:9be122c18509 1571 DownLinkCounter = downLinkCounter = sequenceCounter;
GregCr 0:9be122c18509 1572 }
GregCr 0:9be122c18509 1573 LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
GregCr 0:9be122c18509 1574 }
GregCr 0:9be122c18509 1575 }
GregCr 0:9be122c18509 1576 else
GregCr 0:9be122c18509 1577 {
GregCr 0:9be122c18509 1578 downLinkCounter = ( downLinkCounter & 0xFFFF0000 ) | sequenceCounter;
GregCr 0:9be122c18509 1579 LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
GregCr 0:9be122c18509 1580 }
GregCr 0:9be122c18509 1581
GregCr 0:9be122c18509 1582 if( ( isMicOk == true ) ||
GregCr 0:9be122c18509 1583 ( micRx == mic ) )
GregCr 0:9be122c18509 1584 {
GregCr 0:9be122c18509 1585 LoRaMacEventFlags.Bits.Rx = 1;
GregCr 0:9be122c18509 1586 LoRaMacEventInfo.RxSnr = snr;
GregCr 0:9be122c18509 1587 LoRaMacEventInfo.RxRssi = rssi;
GregCr 0:9be122c18509 1588 LoRaMacEventInfo.RxBufferSize = 0;
GregCr 0:9be122c18509 1589 AdrAckCounter = 0;
GregCr 0:9be122c18509 1590 if( LoRaMacEventFlags.Bits.Multicast == 1 )
GregCr 0:9be122c18509 1591 {
GregCr 0:9be122c18509 1592 curMulticastParams->DownLinkCounter = downLinkCounter;
GregCr 0:9be122c18509 1593 }
GregCr 0:9be122c18509 1594 else
GregCr 0:9be122c18509 1595 {
GregCr 0:9be122c18509 1596 DownLinkCounter = downLinkCounter;
GregCr 0:9be122c18509 1597 }
GregCr 0:9be122c18509 1598
GregCr 0:9be122c18509 1599 if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
GregCr 0:9be122c18509 1600 {
GregCr 0:9be122c18509 1601 SrvAckRequested = true;
GregCr 0:9be122c18509 1602 }
GregCr 0:9be122c18509 1603 else
GregCr 0:9be122c18509 1604 {
GregCr 0:9be122c18509 1605 SrvAckRequested = false;
GregCr 0:9be122c18509 1606 }
GregCr 0:9be122c18509 1607 // Check if the frame is an acknowledgement
GregCr 0:9be122c18509 1608 if( fCtrl.Bits.Ack == 1 )
GregCr 0:9be122c18509 1609 {
GregCr 0:9be122c18509 1610 LoRaMacEventInfo.TxAckReceived = true;
GregCr 0:9be122c18509 1611
GregCr 0:9be122c18509 1612 // Stop the AckTimeout timer as no more retransmissions
GregCr 0:9be122c18509 1613 // are needed.
GregCr 0:9be122c18509 1614 AckTimeoutTimer.detach( );
GregCr 0:9be122c18509 1615 }
GregCr 0:9be122c18509 1616 else
GregCr 0:9be122c18509 1617 {
GregCr 0:9be122c18509 1618 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 1619 if( AckTimeoutRetriesCounter > AckTimeoutRetries )
GregCr 0:9be122c18509 1620 {
GregCr 0:9be122c18509 1621 // Stop the AckTimeout timer as no more retransmissions
GregCr 0:9be122c18509 1622 // are needed.
GregCr 0:9be122c18509 1623 AckTimeoutTimer.detach( );
GregCr 0:9be122c18509 1624 }
GregCr 0:9be122c18509 1625 }
GregCr 0:9be122c18509 1626
GregCr 0:9be122c18509 1627 if( fCtrl.Bits.FOptsLen > 0 )
GregCr 0:9be122c18509 1628 {
GregCr 0:9be122c18509 1629 // Decode Options field MAC commands
GregCr 0:9be122c18509 1630 LoRaMacProcessMacCommands( payload, 8, appPayloadStartIndex );
GregCr 0:9be122c18509 1631 }
GregCr 0:9be122c18509 1632
GregCr 0:9be122c18509 1633 if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
GregCr 0:9be122c18509 1634 {
GregCr 0:9be122c18509 1635 port = payload[appPayloadStartIndex++];
GregCr 0:9be122c18509 1636 frameLen = ( size - 4 ) - appPayloadStartIndex;
GregCr 0:9be122c18509 1637
GregCr 0:9be122c18509 1638 if( port == 0 )
GregCr 0:9be122c18509 1639 {
GregCr 0:9be122c18509 1640 LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
GregCr 0:9be122c18509 1641 frameLen,
GregCr 0:9be122c18509 1642 nwkSKey,
GregCr 0:9be122c18509 1643 address,
GregCr 0:9be122c18509 1644 DOWN_LINK,
GregCr 0:9be122c18509 1645 downLinkCounter,
GregCr 0:9be122c18509 1646 LoRaMacRxPayload );
GregCr 0:9be122c18509 1647
GregCr 0:9be122c18509 1648 // Decode frame payload MAC commands
GregCr 0:9be122c18509 1649 LoRaMacProcessMacCommands( LoRaMacRxPayload, 0, frameLen );
GregCr 0:9be122c18509 1650 }
GregCr 0:9be122c18509 1651 else
GregCr 0:9be122c18509 1652 {
GregCr 0:9be122c18509 1653 LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
GregCr 0:9be122c18509 1654 frameLen,
GregCr 0:9be122c18509 1655 appSKey,
GregCr 0:9be122c18509 1656 address,
GregCr 0:9be122c18509 1657 DOWN_LINK,
GregCr 0:9be122c18509 1658 downLinkCounter,
GregCr 0:9be122c18509 1659 LoRaMacRxPayload );
GregCr 0:9be122c18509 1660
GregCr 0:9be122c18509 1661 LoRaMacEventFlags.Bits.RxData = 1;
GregCr 0:9be122c18509 1662 LoRaMacEventInfo.RxPort = port;
GregCr 0:9be122c18509 1663 LoRaMacEventInfo.RxBuffer = LoRaMacRxPayload;
GregCr 0:9be122c18509 1664 LoRaMacEventInfo.RxBufferSize = frameLen;
GregCr 0:9be122c18509 1665 }
GregCr 0:9be122c18509 1666 }
GregCr 0:9be122c18509 1667
GregCr 0:9be122c18509 1668 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1669 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1670 }
GregCr 0:9be122c18509 1671 else
GregCr 0:9be122c18509 1672 {
GregCr 0:9be122c18509 1673 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 1674
GregCr 0:9be122c18509 1675 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1676 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
GregCr 0:9be122c18509 1677 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1678 }
GregCr 0:9be122c18509 1679 }
GregCr 0:9be122c18509 1680 break;
GregCr 0:9be122c18509 1681 case FRAME_TYPE_PROPRIETARY:
GregCr 0:9be122c18509 1682 //Intentional falltrough
GregCr 0:9be122c18509 1683 default:
GregCr 0:9be122c18509 1684 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1685 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
GregCr 0:9be122c18509 1686 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1687 break;
GregCr 0:9be122c18509 1688 }
GregCr 0:9be122c18509 1689 }
GregCr 0:9be122c18509 1690
GregCr 0:9be122c18509 1691 /*!
GregCr 0:9be122c18509 1692 * Function executed on Radio Tx Timeout event
GregCr 0:9be122c18509 1693 */
GregCr 0:9be122c18509 1694 static void OnRadioTxTimeout( void )
GregCr 1:0a272b37c6cd 1695 {
GregCr 0:9be122c18509 1696 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1697 {
GregCr 0:9be122c18509 1698 Radio.Sleep( );
GregCr 0:9be122c18509 1699 }
GregCr 0:9be122c18509 1700 else
GregCr 0:9be122c18509 1701 {
GregCr 0:9be122c18509 1702 OnRxWindow2TimerEvent( );
GregCr 0:9be122c18509 1703 }
GregCr 0:9be122c18509 1704
GregCr 0:9be122c18509 1705 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1706 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
GregCr 0:9be122c18509 1707 }
GregCr 0:9be122c18509 1708
GregCr 0:9be122c18509 1709 /*!
GregCr 0:9be122c18509 1710 * Function executed on Radio Rx Timeout event
GregCr 0:9be122c18509 1711 */
GregCr 0:9be122c18509 1712 static void OnRadioRxTimeout( void )
GregCr 1:0a272b37c6cd 1713 {
GregCr 0:9be122c18509 1714 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1715 {
GregCr 0:9be122c18509 1716 Radio.Sleep( );
GregCr 0:9be122c18509 1717 }
GregCr 0:9be122c18509 1718 if( LoRaMacEventFlags.Bits.RxSlot == 1 )
GregCr 0:9be122c18509 1719 {
GregCr 0:9be122c18509 1720 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1721 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
GregCr 0:9be122c18509 1722 }
GregCr 0:9be122c18509 1723 }
GregCr 0:9be122c18509 1724
GregCr 0:9be122c18509 1725 /*!
GregCr 0:9be122c18509 1726 * Function executed on Radio Rx Error event
GregCr 0:9be122c18509 1727 */
GregCr 0:9be122c18509 1728 static void OnRadioRxError( void )
GregCr 1:0a272b37c6cd 1729 {
GregCr 0:9be122c18509 1730 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1731 {
GregCr 0:9be122c18509 1732 Radio.Sleep( );
GregCr 0:9be122c18509 1733 }
GregCr 0:9be122c18509 1734 if( LoRaMacEventFlags.Bits.RxSlot == 1 )
GregCr 0:9be122c18509 1735 {
GregCr 0:9be122c18509 1736 LoRaMacEventFlags.Bits.Tx = 1;
GregCr 0:9be122c18509 1737 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
GregCr 0:9be122c18509 1738 }
GregCr 0:9be122c18509 1739 }
GregCr 0:9be122c18509 1740
GregCr 0:9be122c18509 1741 /*!
GregCr 0:9be122c18509 1742 * Initializes and opens the reception window
GregCr 0:9be122c18509 1743 *
GregCr 0:9be122c18509 1744 * \param [IN] freq window channel frequency
GregCr 0:9be122c18509 1745 * \param [IN] datarate window channel datarate
GregCr 0:9be122c18509 1746 * \param [IN] bandwidth window channel bandwidth
GregCr 0:9be122c18509 1747 * \param [IN] timeout window channel timeout
GregCr 0:9be122c18509 1748 */
GregCr 0:9be122c18509 1749 void LoRaMacRxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous )
GregCr 0:9be122c18509 1750 {
GregCr 0:9be122c18509 1751 if( Radio.GetStatus( ) == IDLE )
GregCr 0:9be122c18509 1752 {
GregCr 0:9be122c18509 1753 Radio.SetChannel( freq );
GregCr 0:9be122c18509 1754 if( datarate == DR_7 )
GregCr 0:9be122c18509 1755 {
GregCr 0:9be122c18509 1756 Radio.SetRxConfig( MODEM_FSK, 50e3, Datarates[datarate] * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, rxContinuous );
GregCr 0:9be122c18509 1757 }
GregCr 0:9be122c18509 1758 else
GregCr 0:9be122c18509 1759 {
GregCr 0:9be122c18509 1760 Radio.SetRxConfig( MODEM_LORA, bandwidth, Datarates[datarate], 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous );
GregCr 0:9be122c18509 1761 }
GregCr 0:9be122c18509 1762 if( rxContinuous == false )
GregCr 0:9be122c18509 1763 {
GregCr 0:9be122c18509 1764 Radio.Rx( MaxRxWindow );
GregCr 0:9be122c18509 1765 }
GregCr 0:9be122c18509 1766 else
GregCr 0:9be122c18509 1767 {
GregCr 0:9be122c18509 1768 Radio.Rx( 0 ); // Continuous mode
GregCr 0:9be122c18509 1769 }
GregCr 0:9be122c18509 1770 }
GregCr 0:9be122c18509 1771 }
GregCr 0:9be122c18509 1772
GregCr 0:9be122c18509 1773 /*!
GregCr 0:9be122c18509 1774 * Function executed on first Rx window timer event
GregCr 0:9be122c18509 1775 */
GregCr 0:9be122c18509 1776 static void OnRxWindow1TimerEvent( void )
GregCr 0:9be122c18509 1777 {
GregCr 3:675d14219ad5 1778 uint16_t symbTimeout = 20; // DR_2, DR_1, DR_0
GregCr 0:9be122c18509 1779 int8_t datarate = 0;
GregCr 0:9be122c18509 1780 uint32_t bandwidth = 0; // LoRa 125 kHz
GregCr 0:9be122c18509 1781
GregCr 1:0a272b37c6cd 1782 RxWindowTimer1.detach( );
GregCr 0:9be122c18509 1783
GregCr 0:9be122c18509 1784 datarate = ChannelsDatarate - Rx1DrOffset;
GregCr 0:9be122c18509 1785 if( datarate < 0 )
GregCr 0:9be122c18509 1786 {
GregCr 0:9be122c18509 1787 datarate = DR_0;
GregCr 0:9be122c18509 1788 }
GregCr 0:9be122c18509 1789
GregCr 0:9be122c18509 1790 // For higher datarates, we increase the number of symbols generating a Rx Timeout
GregCr 0:9be122c18509 1791 if( datarate >= DR_3 )
GregCr 0:9be122c18509 1792 { // DR_6, DR_5, DR_4, DR_3
GregCr 3:675d14219ad5 1793 symbTimeout = 50;
GregCr 0:9be122c18509 1794 }
GregCr 0:9be122c18509 1795 if( datarate == DR_6 )
GregCr 0:9be122c18509 1796 {// LoRa 250 kHz
GregCr 0:9be122c18509 1797 bandwidth = 1;
GregCr 0:9be122c18509 1798 }
GregCr 0:9be122c18509 1799 LoRaMacEventFlags.Bits.RxSlot = 0;
GregCr 0:9be122c18509 1800 LoRaMacRxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false );
GregCr 0:9be122c18509 1801 }
GregCr 0:9be122c18509 1802
GregCr 0:9be122c18509 1803 /*!
GregCr 0:9be122c18509 1804 * Function executed on second Rx window timer event
GregCr 0:9be122c18509 1805 */
GregCr 0:9be122c18509 1806 static void OnRxWindow2TimerEvent( void )
GregCr 0:9be122c18509 1807 {
GregCr 1:0a272b37c6cd 1808 RxWindowTimer2.detach( );
GregCr 0:9be122c18509 1809
GregCr 0:9be122c18509 1810 if( NodeAckRequested == true )
GregCr 0:9be122c18509 1811 {
GregCr 0:9be122c18509 1812 AckTimeoutTimer.attach_us( &OnAckTimeoutTimerEvent, ACK_TIMEOUT + randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
GregCr 0:9be122c18509 1813 }
GregCr 0:9be122c18509 1814
GregCr 3:675d14219ad5 1815 uint16_t symbTimeout = 20; // DR_2, DR_1, DR_0
GregCr 0:9be122c18509 1816 uint32_t bandwidth = 0; // LoRa 125 kHz
GregCr 0:9be122c18509 1817
GregCr 0:9be122c18509 1818 // For higher datarates, we increase the number of symbols generating a Rx Timeout
GregCr 0:9be122c18509 1819 if( Rx2Channel.Datarate >= DR_3 )
GregCr 0:9be122c18509 1820 { // DR_6, DR_5, DR_4, DR_3
GregCr 3:675d14219ad5 1821 symbTimeout = 50;
GregCr 0:9be122c18509 1822 }
GregCr 0:9be122c18509 1823 if( Rx2Channel.Datarate == DR_6 )
GregCr 0:9be122c18509 1824 {// LoRa 250 kHz
GregCr 0:9be122c18509 1825 bandwidth = 1;
GregCr 0:9be122c18509 1826 }
GregCr 0:9be122c18509 1827
GregCr 0:9be122c18509 1828 LoRaMacEventFlags.Bits.RxSlot = 1;
GregCr 0:9be122c18509 1829 if( LoRaMacDeviceClass != CLASS_C )
GregCr 0:9be122c18509 1830 {
GregCr 0:9be122c18509 1831 LoRaMacRxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, false );
GregCr 0:9be122c18509 1832 }
GregCr 0:9be122c18509 1833 else
GregCr 0:9be122c18509 1834 {
GregCr 0:9be122c18509 1835 LoRaMacRxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, true );
GregCr 0:9be122c18509 1836 }
GregCr 0:9be122c18509 1837 }
GregCr 0:9be122c18509 1838
GregCr 0:9be122c18509 1839 /*!
GregCr 0:9be122c18509 1840 * Function executed on MacStateCheck timer event
GregCr 0:9be122c18509 1841 */
GregCr 0:9be122c18509 1842 static void OnMacStateCheckTimerEvent( void )
GregCr 0:9be122c18509 1843 {
GregCr 1:0a272b37c6cd 1844 MacStateCheckTimer.detach( );
GregCr 0:9be122c18509 1845
GregCr 0:9be122c18509 1846 if( LoRaMacEventFlags.Bits.Tx == 1 )
GregCr 0:9be122c18509 1847 {
GregCr 0:9be122c18509 1848 if( NodeAckRequested == false )
GregCr 0:9be122c18509 1849 {
GregCr 0:9be122c18509 1850 if( LoRaMacEventFlags.Bits.JoinAccept == true )
GregCr 0:9be122c18509 1851 {
GregCr 0:9be122c18509 1852 // Join messages aren't repeated automatically
GregCr 0:9be122c18509 1853 ChannelsNbRepCounter = ChannelsNbRep;
GregCr 0:9be122c18509 1854 UpLinkCounter = 0;
GregCr 0:9be122c18509 1855 }
GregCr 0:9be122c18509 1856 if( ChannelsNbRepCounter >= ChannelsNbRep )
GregCr 0:9be122c18509 1857 {
GregCr 0:9be122c18509 1858 ChannelsNbRepCounter = 0;
GregCr 0:9be122c18509 1859
GregCr 0:9be122c18509 1860 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1861
GregCr 0:9be122c18509 1862 AdrAckCounter++;
GregCr 0:9be122c18509 1863 if( IsUpLinkCounterFixed == false )
GregCr 0:9be122c18509 1864 {
GregCr 0:9be122c18509 1865 UpLinkCounter++;
GregCr 0:9be122c18509 1866 }
GregCr 0:9be122c18509 1867
GregCr 0:9be122c18509 1868 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1869 }
GregCr 0:9be122c18509 1870 else
GregCr 0:9be122c18509 1871 {
GregCr 0:9be122c18509 1872 LoRaMacEventFlags.Bits.Tx = 0;
GregCr 0:9be122c18509 1873 // Sends the same frame again
GregCr 0:9be122c18509 1874 if( LoRaMacSetNextChannel( ) == 0 )
GregCr 0:9be122c18509 1875 {
GregCr 0:9be122c18509 1876 LoRaMacSendFrameOnChannel( Channels[Channel] );
GregCr 0:9be122c18509 1877 }
GregCr 0:9be122c18509 1878 }
GregCr 0:9be122c18509 1879 }
GregCr 0:9be122c18509 1880
GregCr 0:9be122c18509 1881 if( LoRaMacEventFlags.Bits.Rx == 1 )
GregCr 0:9be122c18509 1882 {
GregCr 0:9be122c18509 1883 if( ( LoRaMacEventInfo.TxAckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) )
GregCr 0:9be122c18509 1884 {
GregCr 0:9be122c18509 1885 AckTimeoutRetry = false;
GregCr 0:9be122c18509 1886 if( IsUpLinkCounterFixed == false )
GregCr 0:9be122c18509 1887 {
GregCr 0:9be122c18509 1888 UpLinkCounter++;
GregCr 0:9be122c18509 1889 }
GregCr 0:9be122c18509 1890 LoRaMacEventInfo.TxNbRetries = AckTimeoutRetriesCounter;
GregCr 0:9be122c18509 1891
GregCr 0:9be122c18509 1892 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1893 }
GregCr 0:9be122c18509 1894 }
GregCr 0:9be122c18509 1895
GregCr 0:9be122c18509 1896 if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & MAC_CHANNEL_CHECK ) == 0 ) )
GregCr 0:9be122c18509 1897 {
GregCr 0:9be122c18509 1898 AckTimeoutRetry = false;
GregCr 0:9be122c18509 1899 if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) )
GregCr 0:9be122c18509 1900 {
GregCr 0:9be122c18509 1901 AckTimeoutRetriesCounter++;
GregCr 0:9be122c18509 1902
GregCr 0:9be122c18509 1903 if( ( AckTimeoutRetriesCounter % 2 ) == 1 )
GregCr 0:9be122c18509 1904 {
GregCr 0:9be122c18509 1905 ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_MIN_DATARATE );
GregCr 0:9be122c18509 1906 }
GregCr 0:9be122c18509 1907 LoRaMacEventFlags.Bits.Tx = 0;
GregCr 0:9be122c18509 1908 // Sends the same frame again
GregCr 0:9be122c18509 1909 if( LoRaMacSetNextChannel( ) == 0 )
GregCr 0:9be122c18509 1910 {
GregCr 0:9be122c18509 1911 LoRaMacSendFrameOnChannel( Channels[Channel] );
GregCr 0:9be122c18509 1912 }
GregCr 0:9be122c18509 1913 }
GregCr 0:9be122c18509 1914 else
GregCr 0:9be122c18509 1915 {
GregCr 0:9be122c18509 1916 // Re-enable default channels LC1, LC2, LC3
GregCr 0:9be122c18509 1917 ChannelsMask = ChannelsMask | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
GregCr 0:9be122c18509 1918
GregCr 0:9be122c18509 1919 LoRaMacState &= ~MAC_TX_RUNNING;
GregCr 0:9be122c18509 1920
GregCr 0:9be122c18509 1921 LoRaMacEventInfo.TxAckReceived = false;
GregCr 0:9be122c18509 1922 LoRaMacEventInfo.TxNbRetries = AckTimeoutRetriesCounter;
GregCr 0:9be122c18509 1923 if( IsUpLinkCounterFixed == false )
GregCr 0:9be122c18509 1924 {
GregCr 0:9be122c18509 1925 UpLinkCounter++;
GregCr 0:9be122c18509 1926 }
GregCr 0:9be122c18509 1927 LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
GregCr 0:9be122c18509 1928 }
GregCr 0:9be122c18509 1929 }
GregCr 0:9be122c18509 1930 }
GregCr 0:9be122c18509 1931 // Handle reception for Class B and Class C
GregCr 0:9be122c18509 1932 if( ( LoRaMacState & MAC_RX ) == MAC_RX )
GregCr 0:9be122c18509 1933 {
GregCr 0:9be122c18509 1934 LoRaMacState &= ~MAC_RX;
GregCr 0:9be122c18509 1935 }
GregCr 0:9be122c18509 1936 if( LoRaMacState == MAC_IDLE )
GregCr 0:9be122c18509 1937 {
GregCr 0:9be122c18509 1938 LoRaMacNotify( &LoRaMacEventFlags, &LoRaMacEventInfo );
GregCr 0:9be122c18509 1939 }
GregCr 0:9be122c18509 1940 else
GregCr 0:9be122c18509 1941 {
GregCr 0:9be122c18509 1942 // Operation not finished restart timer
GregCr 0:9be122c18509 1943 MacStateCheckTimer.attach_us( &OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT );
GregCr 0:9be122c18509 1944 }
GregCr 0:9be122c18509 1945 }
GregCr 0:9be122c18509 1946
GregCr 0:9be122c18509 1947 static void OnAckTimeoutTimerEvent( void )
GregCr 0:9be122c18509 1948 {
GregCr 1:0a272b37c6cd 1949 AckTimeoutTimer.detach( );
GregCr 0:9be122c18509 1950
GregCr 0:9be122c18509 1951 AckTimeoutRetry = true;
GregCr 0:9be122c18509 1952 LoRaMacState &= ~MAC_ACK_REQ;
GregCr 0:9be122c18509 1953 }
GregCr 0:9be122c18509 1954
GregCr 0:9be122c18509 1955 /*!
GregCr 0:9be122c18509 1956 * ============================================================================
GregCr 0:9be122c18509 1957 * = LoRaMac test functions =
GregCr 0:9be122c18509 1958 * ============================================================================
GregCr 0:9be122c18509 1959 */
GregCr 0:9be122c18509 1960
GregCr 0:9be122c18509 1961 void LoRaMacSetDeviceClass( DeviceClass_t deviceClass )
GregCr 0:9be122c18509 1962 {
GregCr 0:9be122c18509 1963 LoRaMacDeviceClass = deviceClass;
GregCr 0:9be122c18509 1964 }
GregCr 0:9be122c18509 1965
GregCr 0:9be122c18509 1966 void LoRaMacSetPublicNetwork( bool enable )
GregCr 0:9be122c18509 1967 {
GregCr 0:9be122c18509 1968 PublicNetwork = enable;
GregCr 0:9be122c18509 1969 Radio.SetModem( MODEM_LORA );
GregCr 0:9be122c18509 1970 if( PublicNetwork == true )
GregCr 0:9be122c18509 1971 {
GregCr 0:9be122c18509 1972 // Change LoRa modem SyncWord
GregCr 0:9be122c18509 1973 Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD );
GregCr 0:9be122c18509 1974 }
GregCr 0:9be122c18509 1975 else
GregCr 0:9be122c18509 1976 {
GregCr 0:9be122c18509 1977 // Change LoRa modem SyncWord
GregCr 0:9be122c18509 1978 Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD );
GregCr 0:9be122c18509 1979 }
GregCr 0:9be122c18509 1980 }
GregCr 0:9be122c18509 1981
GregCr 0:9be122c18509 1982 void LoRaMacSetDutyCycleOn( bool enable )
GregCr 0:9be122c18509 1983 {
GregCr 0:9be122c18509 1984 DutyCycleOn = enable;
GregCr 0:9be122c18509 1985 }
GregCr 0:9be122c18509 1986
GregCr 0:9be122c18509 1987 void LoRaMacSetChannel( uint8_t id, ChannelParams_t params )
GregCr 0:9be122c18509 1988 {
GregCr 0:9be122c18509 1989 params.Band = 0;
GregCr 0:9be122c18509 1990 Channels[id] = params;
GregCr 0:9be122c18509 1991 // Activate the newly created channel
GregCr 0:9be122c18509 1992 ChannelsMask |= 1 << id;
GregCr 0:9be122c18509 1993
GregCr 0:9be122c18509 1994 #if defined( USE_BAND_868 )
GregCr 0:9be122c18509 1995 if( ( Channels[id].Frequency >= 865000000 ) && ( Channels[id].Frequency <= 868000000 ) )
GregCr 0:9be122c18509 1996 {
GregCr 0:9be122c18509 1997 if( Channels[id].Band != BAND_G1_0 )
GregCr 0:9be122c18509 1998 {
GregCr 0:9be122c18509 1999 Channels[id].Band = BAND_G1_0;
GregCr 0:9be122c18509 2000 }
GregCr 0:9be122c18509 2001 }
GregCr 0:9be122c18509 2002 else if( ( Channels[id].Frequency > 868000000 ) && ( Channels[id].Frequency <= 868600000 ) )
GregCr 0:9be122c18509 2003 {
GregCr 0:9be122c18509 2004 if( Channels[id].Band != BAND_G1_1 )
GregCr 0:9be122c18509 2005 {
GregCr 0:9be122c18509 2006 Channels[id].Band = BAND_G1_1;
GregCr 0:9be122c18509 2007 }
GregCr 0:9be122c18509 2008 }
GregCr 0:9be122c18509 2009 else if( ( Channels[id].Frequency >= 868700000 ) && ( Channels[id].Frequency <= 869200000 ) )
GregCr 0:9be122c18509 2010 {
GregCr 0:9be122c18509 2011 if( Channels[id].Band != BAND_G1_2 )
GregCr 0:9be122c18509 2012 {
GregCr 0:9be122c18509 2013 Channels[id].Band = BAND_G1_2;
GregCr 0:9be122c18509 2014 }
GregCr 0:9be122c18509 2015 }
GregCr 0:9be122c18509 2016 else if( ( Channels[id].Frequency >= 869400000 ) && ( Channels[id].Frequency <= 869650000 ) )
GregCr 0:9be122c18509 2017 {
GregCr 0:9be122c18509 2018 if( Channels[id].Band != BAND_G1_3 )
GregCr 0:9be122c18509 2019 {
GregCr 0:9be122c18509 2020 Channels[id].Band = BAND_G1_3;
GregCr 0:9be122c18509 2021 }
GregCr 0:9be122c18509 2022 }
GregCr 0:9be122c18509 2023 else if( ( Channels[id].Frequency >= 869700000 ) && ( Channels[id].Frequency <= 870000000 ) )
GregCr 0:9be122c18509 2024 {
GregCr 0:9be122c18509 2025 if( Channels[id].Band != BAND_G1_4 )
GregCr 0:9be122c18509 2026 {
GregCr 0:9be122c18509 2027 Channels[id].Band = BAND_G1_4;
GregCr 0:9be122c18509 2028 }
GregCr 0:9be122c18509 2029 }
GregCr 0:9be122c18509 2030 else
GregCr 0:9be122c18509 2031 {
GregCr 0:9be122c18509 2032 Channels[id].Frequency = 0;
GregCr 0:9be122c18509 2033 Channels[id].DrRange.Value = 0;
GregCr 0:9be122c18509 2034 }
GregCr 0:9be122c18509 2035 #endif
GregCr 0:9be122c18509 2036 // Check if it is a valid channel
GregCr 0:9be122c18509 2037 if( Channels[id].Frequency == 0 )
GregCr 0:9be122c18509 2038 {
GregCr 0:9be122c18509 2039 ChannelsMask &= ~( 1 << id );
GregCr 0:9be122c18509 2040 }
GregCr 0:9be122c18509 2041 }
GregCr 0:9be122c18509 2042
GregCr 0:9be122c18509 2043 void LoRaMacSetRx2Channel( Rx2ChannelParams_t param )
GregCr 0:9be122c18509 2044 {
GregCr 0:9be122c18509 2045 Rx2Channel = param;
GregCr 0:9be122c18509 2046 }
GregCr 0:9be122c18509 2047
GregCr 0:9be122c18509 2048 void LoRaMacSetChannelsTxPower( int8_t txPower )
GregCr 0:9be122c18509 2049 {
GregCr 0:9be122c18509 2050 ChannelsTxPower = txPower;
GregCr 0:9be122c18509 2051 }
GregCr 0:9be122c18509 2052
GregCr 0:9be122c18509 2053 void LoRaMacSetChannelsDatarate( int8_t datarate )
GregCr 0:9be122c18509 2054 {
GregCr 0:9be122c18509 2055 ChannelsDefaultDatarate = ChannelsDatarate = datarate;
GregCr 0:9be122c18509 2056 }
GregCr 0:9be122c18509 2057
GregCr 0:9be122c18509 2058 void LoRaMacSetChannelsMask( uint16_t mask )
GregCr 0:9be122c18509 2059 {
GregCr 0:9be122c18509 2060 ChannelsMask = mask;
GregCr 0:9be122c18509 2061 }
GregCr 0:9be122c18509 2062
GregCr 0:9be122c18509 2063 void LoRaMacSetChannelsNbRep( uint8_t nbRep )
GregCr 0:9be122c18509 2064 {
GregCr 0:9be122c18509 2065 if( nbRep < 1 )
GregCr 0:9be122c18509 2066 {
GregCr 0:9be122c18509 2067 nbRep = 1;
GregCr 0:9be122c18509 2068 }
GregCr 0:9be122c18509 2069 if( nbRep > 15 )
GregCr 0:9be122c18509 2070 {
GregCr 0:9be122c18509 2071 nbRep = 15;
GregCr 0:9be122c18509 2072 }
GregCr 0:9be122c18509 2073 ChannelsNbRep = nbRep;
GregCr 0:9be122c18509 2074 }
GregCr 0:9be122c18509 2075
GregCr 0:9be122c18509 2076 void LoRaMacSetMaxRxWindow( uint32_t delay )
GregCr 0:9be122c18509 2077 {
GregCr 0:9be122c18509 2078 MaxRxWindow = delay;
GregCr 0:9be122c18509 2079 }
GregCr 0:9be122c18509 2080
GregCr 0:9be122c18509 2081 void LoRaMacSetReceiveDelay1( uint32_t delay )
GregCr 0:9be122c18509 2082 {
GregCr 0:9be122c18509 2083 ReceiveDelay1 = delay;
GregCr 0:9be122c18509 2084 }
GregCr 0:9be122c18509 2085
GregCr 0:9be122c18509 2086 void LoRaMacSetReceiveDelay2( uint32_t delay )
GregCr 0:9be122c18509 2087 {
GregCr 0:9be122c18509 2088 ReceiveDelay2 = delay;
GregCr 0:9be122c18509 2089 }
GregCr 0:9be122c18509 2090
GregCr 0:9be122c18509 2091 void LoRaMacSetJoinAcceptDelay1( uint32_t delay )
GregCr 0:9be122c18509 2092 {
GregCr 0:9be122c18509 2093 JoinAcceptDelay1 = delay;
GregCr 0:9be122c18509 2094 }
GregCr 0:9be122c18509 2095
GregCr 0:9be122c18509 2096 void LoRaMacSetJoinAcceptDelay2( uint32_t delay )
GregCr 0:9be122c18509 2097 {
GregCr 0:9be122c18509 2098 JoinAcceptDelay2 = delay;
GregCr 0:9be122c18509 2099 }
GregCr 0:9be122c18509 2100
GregCr 0:9be122c18509 2101 void LoRaMacTestRxWindowsOn( bool enable )
GregCr 0:9be122c18509 2102 {
GregCr 0:9be122c18509 2103 IsRxWindowsEnabled = enable;
GregCr 0:9be122c18509 2104 }
GregCr 0:9be122c18509 2105
GregCr 0:9be122c18509 2106 uint32_t LoRaMacGetUpLinkCounter( void )
GregCr 0:9be122c18509 2107 {
GregCr 0:9be122c18509 2108 return UpLinkCounter;
GregCr 0:9be122c18509 2109 }
GregCr 0:9be122c18509 2110
GregCr 0:9be122c18509 2111 uint32_t LoRaMacGetDownLinkCounter( void )
GregCr 0:9be122c18509 2112 {
GregCr 0:9be122c18509 2113 return DownLinkCounter;
GregCr 0:9be122c18509 2114 }
GregCr 0:9be122c18509 2115
GregCr 0:9be122c18509 2116 void LoRaMacSetMicTest( uint16_t upLinkCounter )
GregCr 0:9be122c18509 2117 {
GregCr 0:9be122c18509 2118 UpLinkCounter = upLinkCounter;
GregCr 0:9be122c18509 2119 IsUpLinkCounterFixed = true;
GregCr 0:9be122c18509 2120 }