Fork of Semtech LoRaWAN stack

Fork of LoRaWAN-lib by canuck lehead

Committer:
Shaun Nelson
Date:
Mon Oct 15 09:15:20 2018 -0400
Branch:
SenetNetTool
Revision:
49:8b9e6442a02a
Parent:
31:930f949fdd9e
Removed static type for up/down counters for access from external code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mluis 0:91d1a7783bb9 1 /*
mluis 0:91d1a7783bb9 2 / _____) _ | |
mluis 0:91d1a7783bb9 3 ( (____ _____ ____ _| |_ _____ ____| |__
mluis 0:91d1a7783bb9 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
mluis 0:91d1a7783bb9 5 _____) ) ____| | | || |_| ____( (___| | | |
mluis 0:91d1a7783bb9 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
mluis 0:91d1a7783bb9 7 (C)2013 Semtech
mluis 2:14a5d6ad92d5 8 ___ _____ _ ___ _ _____ ___ ___ ___ ___
mluis 2:14a5d6ad92d5 9 / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
mluis 2:14a5d6ad92d5 10 \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
mluis 2:14a5d6ad92d5 11 |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
mluis 2:14a5d6ad92d5 12 embedded.connectivity.solutions===============
mluis 0:91d1a7783bb9 13
mluis 0:91d1a7783bb9 14 Description: LoRa MAC layer implementation
mluis 0:91d1a7783bb9 15
mluis 0:91d1a7783bb9 16 License: Revised BSD License, see LICENSE.TXT file include in the project
mluis 0:91d1a7783bb9 17
Shaun Nelson 49:8b9e6442a02a 18 Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel
Shaun Nelson 49:8b9e6442a02a 19 Jäckle ( STACKFORCE )
mluis 0:91d1a7783bb9 20 */
mluis 0:91d1a7783bb9 21 #include "board.h"
mluis 0:91d1a7783bb9 22
mluis 0:91d1a7783bb9 23 #include "LoRaMacCrypto.h"
mluis 0:91d1a7783bb9 24 #include "LoRaMac.h"
mluis 2:14a5d6ad92d5 25 #include "LoRaMacTest.h"
mluis 0:91d1a7783bb9 26
mluis 0:91d1a7783bb9 27 /*!
mluis 0:91d1a7783bb9 28 * Maximum PHY layer payload size
mluis 0:91d1a7783bb9 29 */
Shaun Nelson 49:8b9e6442a02a 30 #define LORAMAC_PHY_MAXPAYLOAD 255
mluis 1:91e4e6c60d1e 31
mluis 1:91e4e6c60d1e 32 /*!
mluis 1:91e4e6c60d1e 33 * Maximum MAC commands buffer size
mluis 1:91e4e6c60d1e 34 */
Shaun Nelson 49:8b9e6442a02a 35 #define LORA_MAC_COMMAND_MAX_LENGTH 15
mluis 0:91d1a7783bb9 36
mluis 0:91d1a7783bb9 37 /*!
mluis 4:37c12dbc8dc7 38 * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength
mluis 4:37c12dbc8dc7 39 * in RxWindowSetup function.
Shaun Nelson 49:8b9e6442a02a 40 * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater +
Shaun Nelson 49:8b9e6442a02a 41 * LORA_MAC_FRMPAYLOAD_OVERHEAD
mluis 4:37c12dbc8dc7 42 */
Shaun Nelson 49:8b9e6442a02a 43 #define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4)
mluis 4:37c12dbc8dc7 44
mluis 4:37c12dbc8dc7 45 /*!
ubhat 20:92764fda7371 46 * Minimum number of available channels in Frequency Hopping Mode
ubhat 20:92764fda7371 47 */
ubhat 20:92764fda7371 48 #define FRQ_HOP_CHNLS_MIN 50
ubhat 20:92764fda7371 49
ubhat 20:92764fda7371 50 /*!
ubhat 20:92764fda7371 51 * Minimum number of available channels in Hybrid Mode
ubhat 20:92764fda7371 52 */
ubhat 20:92764fda7371 53 #define HYBRD_CHNLS_MIN 4
ubhat 20:92764fda7371 54
ubhat 20:92764fda7371 55 /*!
mluis 0:91d1a7783bb9 56 * Device IEEE EUI
mluis 0:91d1a7783bb9 57 */
Shaun Nelson 49:8b9e6442a02a 58 static uint8_t* LoRaMacDevEui;
mluis 0:91d1a7783bb9 59
mluis 0:91d1a7783bb9 60 /*!
mluis 0:91d1a7783bb9 61 * Application IEEE EUI
mluis 0:91d1a7783bb9 62 */
Shaun Nelson 49:8b9e6442a02a 63 static uint8_t* LoRaMacAppEui;
mluis 0:91d1a7783bb9 64
mluis 0:91d1a7783bb9 65 /*!
mluis 0:91d1a7783bb9 66 * AES encryption/decryption cipher application key
mluis 0:91d1a7783bb9 67 */
Shaun Nelson 49:8b9e6442a02a 68 static uint8_t* LoRaMacAppKey;
mluis 0:91d1a7783bb9 69
mluis 0:91d1a7783bb9 70 /*!
mluis 0:91d1a7783bb9 71 * AES encryption/decryption cipher network session key
mluis 0:91d1a7783bb9 72 */
Shaun Nelson 49:8b9e6442a02a 73 static uint8_t LoRaMacNwkSKey[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Shaun Nelson 49:8b9e6442a02a 74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
mluis 0:91d1a7783bb9 75
mluis 0:91d1a7783bb9 76 /*!
mluis 0:91d1a7783bb9 77 * AES encryption/decryption cipher application session key
mluis 0:91d1a7783bb9 78 */
Shaun Nelson 49:8b9e6442a02a 79 static uint8_t LoRaMacAppSKey[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Shaun Nelson 49:8b9e6442a02a 80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
mluis 0:91d1a7783bb9 81
mluis 0:91d1a7783bb9 82 /*!
mluis 0:91d1a7783bb9 83 * Device nonce is a random value extracted by issuing a sequence of RSSI
mluis 0:91d1a7783bb9 84 * measurements
mluis 0:91d1a7783bb9 85 */
mluis 0:91d1a7783bb9 86 static uint16_t LoRaMacDevNonce;
mluis 0:91d1a7783bb9 87
mluis 0:91d1a7783bb9 88 /*!
mluis 0:91d1a7783bb9 89 * Network ID ( 3 bytes )
mluis 0:91d1a7783bb9 90 */
mluis 0:91d1a7783bb9 91 static uint32_t LoRaMacNetID;
mluis 0:91d1a7783bb9 92
mluis 0:91d1a7783bb9 93 /*!
mluis 0:91d1a7783bb9 94 * Mote Address
mluis 0:91d1a7783bb9 95 */
mluis 0:91d1a7783bb9 96 static uint32_t LoRaMacDevAddr;
mluis 0:91d1a7783bb9 97
mluis 0:91d1a7783bb9 98 /*!
mluis 2:14a5d6ad92d5 99 * Multicast channels linked list
mluis 0:91d1a7783bb9 100 */
Shaun Nelson 49:8b9e6442a02a 101 static MulticastParams_t* MulticastChannels = NULL;
mluis 0:91d1a7783bb9 102
mluis 0:91d1a7783bb9 103 /*!
mluis 0:91d1a7783bb9 104 * Actual device class
mluis 0:91d1a7783bb9 105 */
mluis 0:91d1a7783bb9 106 static DeviceClass_t LoRaMacDeviceClass;
mluis 0:91d1a7783bb9 107
mluis 0:91d1a7783bb9 108 /*!
mluis 0:91d1a7783bb9 109 * Indicates if the node is connected to a private or public network
mluis 0:91d1a7783bb9 110 */
mluis 0:91d1a7783bb9 111 static bool PublicNetwork;
mluis 0:91d1a7783bb9 112
mluis 0:91d1a7783bb9 113 /*!
mluis 0:91d1a7783bb9 114 * Indicates if the node supports repeaters
mluis 0:91d1a7783bb9 115 */
mluis 0:91d1a7783bb9 116 static bool RepeaterSupport;
mluis 0:91d1a7783bb9 117
mluis 0:91d1a7783bb9 118 /*!
mluis 0:91d1a7783bb9 119 * Buffer containing the data to be sent or received.
mluis 0:91d1a7783bb9 120 */
mluis 0:91d1a7783bb9 121 static uint8_t LoRaMacBuffer[LORAMAC_PHY_MAXPAYLOAD];
mluis 0:91d1a7783bb9 122
mluis 0:91d1a7783bb9 123 /*!
mluis 0:91d1a7783bb9 124 * Length of packet in LoRaMacBuffer
mluis 0:91d1a7783bb9 125 */
mluis 0:91d1a7783bb9 126 static uint16_t LoRaMacBufferPktLen = 0;
mluis 0:91d1a7783bb9 127
mluis 0:91d1a7783bb9 128 /*!
mluis 0:91d1a7783bb9 129 * Buffer containing the upper layer data.
mluis 0:91d1a7783bb9 130 */
mluis 0:91d1a7783bb9 131 static uint8_t LoRaMacPayload[LORAMAC_PHY_MAXPAYLOAD];
mluis 0:91d1a7783bb9 132 static uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD];
mluis 0:91d1a7783bb9 133
mluis 0:91d1a7783bb9 134 /*!
mluis 0:91d1a7783bb9 135 * LoRaMAC frame counter. Each time a packet is sent the counter is incremented.
mluis 0:91d1a7783bb9 136 * Only the 16 LSB bits are sent
mluis 0:91d1a7783bb9 137 */
Shaun Nelson 49:8b9e6442a02a 138 uint32_t UpLinkCounter = 1;
mluis 0:91d1a7783bb9 139
mluis 0:91d1a7783bb9 140 /*!
Shaun Nelson 49:8b9e6442a02a 141 * LoRaMAC frame counter. Each time a packet is received the counter is
Shaun Nelson 49:8b9e6442a02a 142 * incremented.
mluis 0:91d1a7783bb9 143 * Only the 16 LSB bits are received
mluis 0:91d1a7783bb9 144 */
Shaun Nelson 49:8b9e6442a02a 145 uint32_t DownLinkCounter = 0;
mluis 0:91d1a7783bb9 146
mluis 0:91d1a7783bb9 147 /*!
mluis 0:91d1a7783bb9 148 * IsPacketCounterFixed enables the MIC field tests by fixing the
mluis 0:91d1a7783bb9 149 * UpLinkCounter value
mluis 0:91d1a7783bb9 150 */
mluis 0:91d1a7783bb9 151 static bool IsUpLinkCounterFixed = false;
mluis 0:91d1a7783bb9 152
mluis 0:91d1a7783bb9 153 /*!
mluis 0:91d1a7783bb9 154 * Used for test purposes. Disables the opening of the reception windows.
mluis 0:91d1a7783bb9 155 */
mluis 0:91d1a7783bb9 156 static bool IsRxWindowsEnabled = true;
mluis 0:91d1a7783bb9 157
mluis 0:91d1a7783bb9 158 /*!
mluis 0:91d1a7783bb9 159 * Indicates if the MAC layer has already joined a network.
mluis 0:91d1a7783bb9 160 */
mluis 0:91d1a7783bb9 161 static bool IsLoRaMacNetworkJoined = false;
mluis 0:91d1a7783bb9 162
mluis 0:91d1a7783bb9 163 /*!
mluis 0:91d1a7783bb9 164 * LoRaMac ADR control status
mluis 0:91d1a7783bb9 165 */
snelson 11:507de2ecd2b3 166 static bool AdrCtrlOn = true;
mluis 0:91d1a7783bb9 167
mluis 0:91d1a7783bb9 168 /*!
mluis 0:91d1a7783bb9 169 * Counts the number of missed ADR acknowledgements
mluis 0:91d1a7783bb9 170 */
mluis 0:91d1a7783bb9 171 static uint32_t AdrAckCounter = 0;
mluis 0:91d1a7783bb9 172
mluis 0:91d1a7783bb9 173 /*!
mluis 0:91d1a7783bb9 174 * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates
mluis 0:91d1a7783bb9 175 * if the nodes needs to manage the server acknowledgement.
mluis 0:91d1a7783bb9 176 */
mluis 0:91d1a7783bb9 177 static bool NodeAckRequested = false;
mluis 0:91d1a7783bb9 178
mluis 0:91d1a7783bb9 179 /*!
Shaun Nelson 49:8b9e6442a02a 180 * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable
Shaun Nelson 49:8b9e6442a02a 181 * indicates
mluis 0:91d1a7783bb9 182 * if the ACK bit must be set for the next transmission
mluis 0:91d1a7783bb9 183 */
mluis 0:91d1a7783bb9 184 static bool SrvAckRequested = false;
mluis 0:91d1a7783bb9 185
mluis 0:91d1a7783bb9 186 /*!
mluis 0:91d1a7783bb9 187 * Indicates if the MAC layer wants to send MAC commands
mluis 0:91d1a7783bb9 188 */
mluis 0:91d1a7783bb9 189 static bool MacCommandsInNextTx = false;
mluis 0:91d1a7783bb9 190
mluis 0:91d1a7783bb9 191 /*!
mluis 0:91d1a7783bb9 192 * Contains the current MacCommandsBuffer index
mluis 0:91d1a7783bb9 193 */
mluis 0:91d1a7783bb9 194 static uint8_t MacCommandsBufferIndex = 0;
mluis 0:91d1a7783bb9 195
mluis 0:91d1a7783bb9 196 /*!
Shaun Nelson 27:cda377b2a41f 197 * Contains the current MacCommandsBuffer index for MAC commands to repeat
Shaun Nelson 27:cda377b2a41f 198 */
Shaun Nelson 27:cda377b2a41f 199 static uint8_t MacCommandsBufferToRepeatIndex = 0;
Shaun Nelson 27:cda377b2a41f 200
Shaun Nelson 27:cda377b2a41f 201 /*!
mluis 0:91d1a7783bb9 202 * Buffer containing the MAC layer commands
mluis 0:91d1a7783bb9 203 */
mluis 1:91e4e6c60d1e 204 static uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
mluis 0:91d1a7783bb9 205
Shaun Nelson 27:cda377b2a41f 206 /*!
Shaun Nelson 27:cda377b2a41f 207 * Buffer containing the MAC layer commands which must be repeated
Shaun Nelson 27:cda377b2a41f 208 */
Shaun Nelson 27:cda377b2a41f 209 static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH];
Shaun Nelson 27:cda377b2a41f 210
Shaun Nelson 49:8b9e6442a02a 211 #if defined(USE_BAND_433)
mluis 0:91d1a7783bb9 212 /*!
mluis 0:91d1a7783bb9 213 * Data rates table definition
mluis 0:91d1a7783bb9 214 */
Shaun Nelson 49:8b9e6442a02a 215 const uint8_t Datarates[] = {12, 11, 10, 9, 8, 7, 7, 50};
mluis 0:91d1a7783bb9 216
mluis 0:91d1a7783bb9 217 /*!
Shaun Nelson 49:8b9e6442a02a 218 * Maximum payload with respect to the datarate index. Cannot operate with
Shaun Nelson 49:8b9e6442a02a 219 * repeater.
mluis 0:91d1a7783bb9 220 */
Shaun Nelson 49:8b9e6442a02a 221 const uint8_t MaxPayloadOfDatarate[] = {59, 59, 59, 123, 250, 250, 250, 250};
mluis 0:91d1a7783bb9 222
mluis 0:91d1a7783bb9 223 /*!
Shaun Nelson 49:8b9e6442a02a 224 * Maximum payload with respect to the datarate index. Can operate with
Shaun Nelson 49:8b9e6442a02a 225 * repeater.
mluis 0:91d1a7783bb9 226 */
Shaun Nelson 49:8b9e6442a02a 227 const uint8_t MaxPayloadOfDatarateRepeater[] = {59, 59, 59, 123, 230, 230, 230, 230};
mluis 0:91d1a7783bb9 228
mluis 0:91d1a7783bb9 229 /*!
mluis 0:91d1a7783bb9 230 * Tx output powers table definition
mluis 0:91d1a7783bb9 231 */
Shaun Nelson 49:8b9e6442a02a 232 const int8_t TxPowers[] = {20, 14, 11, 8, 5, 2};
mluis 0:91d1a7783bb9 233
mluis 0:91d1a7783bb9 234 /*!
mluis 0:91d1a7783bb9 235 * LoRaMac bands
mluis 0:91d1a7783bb9 236 */
Shaun Nelson 49:8b9e6442a02a 237 static Band_t Bands[LORA_MAX_NB_BANDS] = {
Shaun Nelson 49:8b9e6442a02a 238 BAND0,
mluis 0:91d1a7783bb9 239 };
mluis 0:91d1a7783bb9 240
mluis 0:91d1a7783bb9 241 /*!
mluis 0:91d1a7783bb9 242 * LoRaMAC channels
mluis 0:91d1a7783bb9 243 */
Shaun Nelson 49:8b9e6442a02a 244 static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = {
Shaun Nelson 49:8b9e6442a02a 245 LC1, LC2, LC3,
mluis 0:91d1a7783bb9 246 };
Shaun Nelson 49:8b9e6442a02a 247 #elif defined(USE_BAND_780)
mluis 0:91d1a7783bb9 248 /*!
mluis 0:91d1a7783bb9 249 * Data rates table definition
mluis 0:91d1a7783bb9 250 */
Shaun Nelson 49:8b9e6442a02a 251 const uint8_t Datarates[] = {12, 11, 10, 9, 8, 7, 7, 50};
mluis 0:91d1a7783bb9 252
mluis 0:91d1a7783bb9 253 /*!
Shaun Nelson 49:8b9e6442a02a 254 * Maximum payload with respect to the datarate index. Cannot operate with
Shaun Nelson 49:8b9e6442a02a 255 * repeater.
mluis 0:91d1a7783bb9 256 */
Shaun Nelson 49:8b9e6442a02a 257 const uint8_t MaxPayloadOfDatarate[] = {59, 59, 59, 123, 250, 250, 250, 250};
mluis 0:91d1a7783bb9 258
mluis 0:91d1a7783bb9 259 /*!
Shaun Nelson 49:8b9e6442a02a 260 * Maximum payload with respect to the datarate index. Can operate with
Shaun Nelson 49:8b9e6442a02a 261 * repeater.
mluis 0:91d1a7783bb9 262 */
Shaun Nelson 49:8b9e6442a02a 263 const uint8_t MaxPayloadOfDatarateRepeater[] = {59, 59, 59, 123, 230, 230, 230, 230};
mluis 0:91d1a7783bb9 264
mluis 0:91d1a7783bb9 265 /*!
mluis 0:91d1a7783bb9 266 * Tx output powers table definition
mluis 0:91d1a7783bb9 267 */
Shaun Nelson 49:8b9e6442a02a 268 const int8_t TxPowers[] = {20, 14, 11, 8, 5, 2};
mluis 0:91d1a7783bb9 269
mluis 0:91d1a7783bb9 270 /*!
mluis 0:91d1a7783bb9 271 * LoRaMac bands
mluis 0:91d1a7783bb9 272 */
Shaun Nelson 49:8b9e6442a02a 273 static Band_t Bands[LORA_MAX_NB_BANDS] = {
Shaun Nelson 49:8b9e6442a02a 274 BAND0,
mluis 0:91d1a7783bb9 275 };
mluis 0:91d1a7783bb9 276
mluis 0:91d1a7783bb9 277 /*!
mluis 0:91d1a7783bb9 278 * LoRaMAC channels
mluis 0:91d1a7783bb9 279 */
Shaun Nelson 49:8b9e6442a02a 280 static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = {
Shaun Nelson 49:8b9e6442a02a 281 LC1, LC2, LC3,
mluis 0:91d1a7783bb9 282 };
Shaun Nelson 49:8b9e6442a02a 283 #elif defined(USE_BAND_868)
mluis 0:91d1a7783bb9 284 /*!
mluis 0:91d1a7783bb9 285 * Data rates table definition
mluis 0:91d1a7783bb9 286 */
Shaun Nelson 49:8b9e6442a02a 287 const uint8_t Datarates[] = {12, 11, 10, 9, 8, 7, 7, 50};
mluis 0:91d1a7783bb9 288
mluis 0:91d1a7783bb9 289 /*!
Shaun Nelson 49:8b9e6442a02a 290 * Maximum payload with respect to the datarate index. Cannot operate with
Shaun Nelson 49:8b9e6442a02a 291 * repeater.
mluis 0:91d1a7783bb9 292 */
Shaun Nelson 49:8b9e6442a02a 293 const uint8_t MaxPayloadOfDatarate[] = {51, 51, 51, 115, 242, 242, 242, 242};
mluis 0:91d1a7783bb9 294
mluis 0:91d1a7783bb9 295 /*!
Shaun Nelson 49:8b9e6442a02a 296 * Maximum payload with respect to the datarate index. Can operate with
Shaun Nelson 49:8b9e6442a02a 297 * repeater.
mluis 0:91d1a7783bb9 298 */
Shaun Nelson 49:8b9e6442a02a 299 const uint8_t MaxPayloadOfDatarateRepeater[] = {51, 51, 51, 115, 222, 222, 222, 222};
mluis 0:91d1a7783bb9 300
mluis 0:91d1a7783bb9 301 /*!
mluis 0:91d1a7783bb9 302 * Tx output powers table definition
mluis 0:91d1a7783bb9 303 */
Shaun Nelson 49:8b9e6442a02a 304 const int8_t TxPowers[] = {20, 14, 11, 8, 5, 2};
mluis 0:91d1a7783bb9 305
mluis 0:91d1a7783bb9 306 /*!
mluis 0:91d1a7783bb9 307 * LoRaMac bands
mluis 0:91d1a7783bb9 308 */
Shaun Nelson 49:8b9e6442a02a 309 static Band_t Bands[LORA_MAX_NB_BANDS] = {
Shaun Nelson 49:8b9e6442a02a 310 BAND0, BAND1, BAND2, BAND3, BAND4,
mluis 0:91d1a7783bb9 311 };
mluis 0:91d1a7783bb9 312
mluis 0:91d1a7783bb9 313 /*!
mluis 0:91d1a7783bb9 314 * LoRaMAC channels
mluis 0:91d1a7783bb9 315 */
Shaun Nelson 49:8b9e6442a02a 316 static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = {
Shaun Nelson 49:8b9e6442a02a 317 LC1, LC2, LC3,
mluis 0:91d1a7783bb9 318 };
Shaun Nelson 49:8b9e6442a02a 319 #elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
mluis 0:91d1a7783bb9 320 /*!
mluis 0:91d1a7783bb9 321 * Data rates table definition
mluis 0:91d1a7783bb9 322 */
Shaun Nelson 49:8b9e6442a02a 323 const uint8_t Datarates[] = {10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0};
mluis 0:91d1a7783bb9 324
mluis 0:91d1a7783bb9 325 /*!
mluis 0:91d1a7783bb9 326 * Up/Down link data rates offset definition
mluis 0:91d1a7783bb9 327 */
Shaun Nelson 49:8b9e6442a02a 328 const uint8_t datarateOffsets[16][4] = {
Shaun Nelson 49:8b9e6442a02a 329 {DR_10, DR_9, DR_8, DR_8}, // DR_0
Shaun Nelson 49:8b9e6442a02a 330 {DR_11, DR_10, DR_9, DR_8}, // DR_1
Shaun Nelson 49:8b9e6442a02a 331 {DR_12, DR_11, DR_10, DR_9}, // DR_2
Shaun Nelson 49:8b9e6442a02a 332 {DR_13, DR_12, DR_11, DR_10}, // DR_3
Shaun Nelson 49:8b9e6442a02a 333 {DR_13, DR_13, DR_12, DR_11}, // DR_4
Shaun Nelson 49:8b9e6442a02a 334 {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
Shaun Nelson 49:8b9e6442a02a 335 {DR_8, DR_8, DR_8, DR_8}, {DR_9, DR_8, DR_8, DR_8}, {DR_10, DR_9, DR_8, DR_8},
Shaun Nelson 49:8b9e6442a02a 336 {DR_11, DR_10, DR_9, DR_8}, {DR_12, DR_11, DR_10, DR_9}, {DR_13, DR_12, DR_11, DR_10},
Shaun Nelson 49:8b9e6442a02a 337 {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
mluis 0:91d1a7783bb9 338 };
mluis 0:91d1a7783bb9 339
mluis 0:91d1a7783bb9 340 /*!
Shaun Nelson 49:8b9e6442a02a 341 * Maximum payload with respect to the datarate index. Cannot operate with
Shaun Nelson 49:8b9e6442a02a 342 * repeater.
mluis 0:91d1a7783bb9 343 */
Shaun Nelson 49:8b9e6442a02a 344 const uint8_t MaxPayloadOfDatarate[] = {11, 53, 126, 242, 242, 0, 0, 0,
Shaun Nelson 49:8b9e6442a02a 345 53, 129, 242, 242, 242, 242, 0, 0};
mluis 0:91d1a7783bb9 346
mluis 0:91d1a7783bb9 347 /*!
Shaun Nelson 49:8b9e6442a02a 348 * Maximum payload with respect to the datarate index. Can operate with
Shaun Nelson 49:8b9e6442a02a 349 * repeater.
mluis 0:91d1a7783bb9 350 */
Shaun Nelson 49:8b9e6442a02a 351 const uint8_t MaxPayloadOfDatarateRepeater[] = {11, 53, 126, 242, 242, 0, 0, 0,
Shaun Nelson 49:8b9e6442a02a 352 33, 109, 222, 222, 222, 222, 0, 0};
mluis 0:91d1a7783bb9 353
mluis 0:91d1a7783bb9 354 /*!
mluis 0:91d1a7783bb9 355 * Tx output powers table definition
mluis 0:91d1a7783bb9 356 */
Shaun Nelson 49:8b9e6442a02a 357 const int8_t TxPowers[] = {30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2};
mluis 0:91d1a7783bb9 358
mluis 0:91d1a7783bb9 359 /*!
mluis 0:91d1a7783bb9 360 * LoRaMac bands
mluis 0:91d1a7783bb9 361 */
Shaun Nelson 49:8b9e6442a02a 362 static Band_t Bands[LORA_MAX_NB_BANDS] = {
Shaun Nelson 49:8b9e6442a02a 363 BAND0,
mluis 0:91d1a7783bb9 364 };
mluis 0:91d1a7783bb9 365
mluis 0:91d1a7783bb9 366 /*!
mluis 0:91d1a7783bb9 367 * LoRaMAC channels
mluis 0:91d1a7783bb9 368 */
mluis 0:91d1a7783bb9 369 static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS];
mluis 0:91d1a7783bb9 370
mluis 2:14a5d6ad92d5 371 /*!
mluis 2:14a5d6ad92d5 372 * Contains the channels which remain to be applied.
mluis 2:14a5d6ad92d5 373 */
mluis 2:14a5d6ad92d5 374 static uint16_t ChannelsMaskRemaining[6];
snelson 8:4816c8449bf2 375
Shaun Nelson 49:8b9e6442a02a 376 #if defined(USE_BAND_915)
snelson 8:4816c8449bf2 377 /*!
Shaun Nelson 49:8b9e6442a02a 378 * Last join request sub-band
snelson 8:4816c8449bf2 379 */
snelson 8:4816c8449bf2 380 static int8_t LastJoinBlock;
snelson 8:4816c8449bf2 381
snelson 8:4816c8449bf2 382 /*!
snelson 8:4816c8449bf2 383 * Next join sub-band block
snelson 8:4816c8449bf2 384 */
Shaun Nelson 49:8b9e6442a02a 385 static uint8_t NextJoinBlock;
Shaun Nelson 49:8b9e6442a02a 386
Shaun Nelson 49:8b9e6442a02a 387 /*!
Shaun Nelson 49:8b9e6442a02a 388 * Mask of 125 KHz sub-bands not used for join transmit
Shaun Nelson 49:8b9e6442a02a 389 */
Shaun Nelson 49:8b9e6442a02a 390 static uint8_t JoinBlocksRemaining;
snelson 8:4816c8449bf2 391
snelson 8:4816c8449bf2 392 /*!
Shaun Nelson 49:8b9e6442a02a 393 * Mask of 500 KHz sub-bands not used for join transmit
snelson 8:4816c8449bf2 394 */
Shaun Nelson 49:8b9e6442a02a 395 static uint8_t Join500KHzRemaining;
snelson 8:4816c8449bf2 396
snelson 8:4816c8449bf2 397 #ifndef JOIN_BLOCK_ORDER
Shaun Nelson 49:8b9e6442a02a 398 #define JOIN_BLOCK_ORDER \
Shaun Nelson 49:8b9e6442a02a 399 { -1, -1, -1, -1, -1, -1, -1, -1 }
snelson 8:4816c8449bf2 400 #endif
snelson 8:4816c8449bf2 401
snelson 8:4816c8449bf2 402 /*!
Shaun Nelson 49:8b9e6442a02a 403 * join sub-band block order
snelson 8:4816c8449bf2 404 */
snelson 8:4816c8449bf2 405 static int8_t JoinBlock[8] = JOIN_BLOCK_ORDER;
snelson 8:4816c8449bf2 406
snelson 8:4816c8449bf2 407 #endif
snelson 8:4816c8449bf2 408
shaunkrnelson 16:1e01c8728daa 409 /*!
shaunkrnelson 16:1e01c8728daa 410 * Defines the first channel for RX window 2 for US band
shaunkrnelson 16:1e01c8728daa 411 */
Shaun Nelson 49:8b9e6442a02a 412 #define LORAMAC_FIRST_RX2_CHANNEL ((uint32_t)923.3e6)
shaunkrnelson 16:1e01c8728daa 413
shaunkrnelson 16:1e01c8728daa 414 /*!
shaunkrnelson 16:1e01c8728daa 415 * Defines the last channel for RX window 2 for US band
shaunkrnelson 16:1e01c8728daa 416 */
Shaun Nelson 49:8b9e6442a02a 417 #define LORAMAC_LAST_RX2_CHANNEL ((uint32_t)927.5e6)
shaunkrnelson 16:1e01c8728daa 418
shaunkrnelson 16:1e01c8728daa 419 /*!
shaunkrnelson 16:1e01c8728daa 420 * Defines the step width of the channels for RX window 2
shaunkrnelson 16:1e01c8728daa 421 */
Shaun Nelson 49:8b9e6442a02a 422 #define LORAMAC_STEPWIDTH_RX2_CHANNEL ((uint32_t)600e3)
shaunkrnelson 16:1e01c8728daa 423
mluis 0:91d1a7783bb9 424 #else
Shaun Nelson 49:8b9e6442a02a 425 #error "Please define a frequency band in the compiler options."
mluis 0:91d1a7783bb9 426 #endif
mluis 0:91d1a7783bb9 427
mluis 0:91d1a7783bb9 428 /*!
mluis 0:91d1a7783bb9 429 * LoRaMAC 2nd reception window settings
mluis 0:91d1a7783bb9 430 */
mluis 0:91d1a7783bb9 431 static Rx2ChannelParams_t Rx2Channel = RX_WND_2_CHANNEL;
mluis 0:91d1a7783bb9 432
mluis 0:91d1a7783bb9 433 /*!
mluis 0:91d1a7783bb9 434 * Datarate offset between uplink and downlink on first window
mluis 0:91d1a7783bb9 435 */
mluis 0:91d1a7783bb9 436 static uint8_t Rx1DrOffset = 0;
mluis 0:91d1a7783bb9 437
mluis 0:91d1a7783bb9 438 /*!
mluis 0:91d1a7783bb9 439 * Mask indicating which channels are enabled
mluis 0:91d1a7783bb9 440 */
mluis 0:91d1a7783bb9 441 static uint16_t ChannelsMask[6];
mluis 0:91d1a7783bb9 442
mluis 0:91d1a7783bb9 443 /*!
mluis 0:91d1a7783bb9 444 * Channels Tx output power
mluis 0:91d1a7783bb9 445 */
mluis 0:91d1a7783bb9 446 static int8_t ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
mluis 0:91d1a7783bb9 447
mluis 0:91d1a7783bb9 448 /*!
mluis 0:91d1a7783bb9 449 * Channels datarate
mluis 0:91d1a7783bb9 450 */
mluis 0:91d1a7783bb9 451 static int8_t ChannelsDatarate = LORAMAC_DEFAULT_DATARATE;
mluis 0:91d1a7783bb9 452
mluis 0:91d1a7783bb9 453 /*!
mluis 0:91d1a7783bb9 454 * Channels default datarate
mluis 0:91d1a7783bb9 455 */
mluis 0:91d1a7783bb9 456 static int8_t ChannelsDefaultDatarate = LORAMAC_DEFAULT_DATARATE;
mluis 0:91d1a7783bb9 457
mluis 0:91d1a7783bb9 458 /*!
mluis 0:91d1a7783bb9 459 * Number of uplink messages repetitions [1:15] (unconfirmed messages only)
mluis 0:91d1a7783bb9 460 */
mluis 0:91d1a7783bb9 461 static uint8_t ChannelsNbRep = 1;
mluis 0:91d1a7783bb9 462
mluis 0:91d1a7783bb9 463 /*!
mluis 0:91d1a7783bb9 464 * Uplink messages repetitions counter
mluis 0:91d1a7783bb9 465 */
mluis 0:91d1a7783bb9 466 static uint8_t ChannelsNbRepCounter = 0;
mluis 0:91d1a7783bb9 467
mluis 0:91d1a7783bb9 468 /*!
mluis 0:91d1a7783bb9 469 * Maximum duty cycle
mluis 0:91d1a7783bb9 470 * \remark Possibility to shutdown the device.
mluis 0:91d1a7783bb9 471 */
mluis 0:91d1a7783bb9 472 static uint8_t MaxDCycle = 0;
mluis 0:91d1a7783bb9 473
mluis 0:91d1a7783bb9 474 /*!
mluis 2:14a5d6ad92d5 475 * Aggregated duty cycle management
mluis 0:91d1a7783bb9 476 */
Shaun Nelson 49:8b9e6442a02a 477 static uint16_t AggregatedDCycle;
mluis 0:91d1a7783bb9 478 static TimerTime_t AggregatedLastTxDoneTime;
mluis 0:91d1a7783bb9 479 static TimerTime_t AggregatedTimeOff;
mluis 0:91d1a7783bb9 480
mluis 0:91d1a7783bb9 481 /*!
mluis 0:91d1a7783bb9 482 * Enables/Disables duty cycle management (Test only)
mluis 0:91d1a7783bb9 483 */
mluis 0:91d1a7783bb9 484 static bool DutyCycleOn;
mluis 0:91d1a7783bb9 485
mluis 0:91d1a7783bb9 486 /*!
mluis 0:91d1a7783bb9 487 * Current channel index
mluis 0:91d1a7783bb9 488 */
mluis 0:91d1a7783bb9 489 static uint8_t Channel;
mluis 0:91d1a7783bb9 490
mluis 4:37c12dbc8dc7 491 static uint8_t LastTxChannel;
mluis 4:37c12dbc8dc7 492
mluis 0:91d1a7783bb9 493 /*!
mluis 0:91d1a7783bb9 494 * LoRaMac internal states
mluis 0:91d1a7783bb9 495 */
Shaun Nelson 49:8b9e6442a02a 496 enum eLoRaMacState {
Shaun Nelson 49:8b9e6442a02a 497 MAC_IDLE = 0x00000000,
Shaun Nelson 49:8b9e6442a02a 498 MAC_TX_RUNNING = 0x00000001,
Shaun Nelson 49:8b9e6442a02a 499 MAC_RX = 0x00000002,
Shaun Nelson 49:8b9e6442a02a 500 MAC_ACK_REQ = 0x00000004,
Shaun Nelson 49:8b9e6442a02a 501 MAC_ACK_RETRY = 0x00000008,
Shaun Nelson 49:8b9e6442a02a 502 MAC_TX_DELAYED = 0x00000010,
Shaun Nelson 49:8b9e6442a02a 503 MAC_TX_CONFIG = 0x00000020,
Shaun Nelson 49:8b9e6442a02a 504 MAC_RX_ABORT = 0x00000040,
mluis 0:91d1a7783bb9 505 };
mluis 0:91d1a7783bb9 506
mluis 0:91d1a7783bb9 507 /*!
mluis 0:91d1a7783bb9 508 * LoRaMac internal state
mluis 0:91d1a7783bb9 509 */
mluis 0:91d1a7783bb9 510 uint32_t LoRaMacState = MAC_IDLE;
mluis 0:91d1a7783bb9 511
mluis 0:91d1a7783bb9 512 /*!
mluis 0:91d1a7783bb9 513 * LoRaMac timer used to check the LoRaMacState (runs every second)
mluis 0:91d1a7783bb9 514 */
mluis 0:91d1a7783bb9 515 static TimerEvent_t MacStateCheckTimer;
mluis 0:91d1a7783bb9 516
mluis 0:91d1a7783bb9 517 /*!
mluis 0:91d1a7783bb9 518 * LoRaMac upper layer event functions
mluis 0:91d1a7783bb9 519 */
Shaun Nelson 49:8b9e6442a02a 520 static LoRaMacPrimitives_t* LoRaMacPrimitives;
mluis 0:91d1a7783bb9 521
mluis 0:91d1a7783bb9 522 /*!
mluis 2:14a5d6ad92d5 523 * LoRaMac upper layer callback functions
mluis 0:91d1a7783bb9 524 */
Shaun Nelson 49:8b9e6442a02a 525 static LoRaMacCallback_t* LoRaMacCallbacks;
mluis 0:91d1a7783bb9 526
mluis 0:91d1a7783bb9 527 /*!
mluis 2:14a5d6ad92d5 528 * Radio events function pointer
mluis 0:91d1a7783bb9 529 */
mluis 2:14a5d6ad92d5 530 static RadioEvents_t RadioEvents;
mluis 0:91d1a7783bb9 531
mluis 0:91d1a7783bb9 532 /*!
mluis 0:91d1a7783bb9 533 * LoRaMac duty cycle delayed Tx timer
mluis 0:91d1a7783bb9 534 */
mluis 0:91d1a7783bb9 535 static TimerEvent_t TxDelayedTimer;
mluis 0:91d1a7783bb9 536
mluis 0:91d1a7783bb9 537 /*!
mluis 0:91d1a7783bb9 538 * LoRaMac reception windows timers
mluis 0:91d1a7783bb9 539 */
mluis 0:91d1a7783bb9 540 static TimerEvent_t RxWindowTimer1;
mluis 0:91d1a7783bb9 541 static TimerEvent_t RxWindowTimer2;
mluis 0:91d1a7783bb9 542
mluis 0:91d1a7783bb9 543 /*!
mluis 0:91d1a7783bb9 544 * LoRaMac reception windows delay from end of Tx
mluis 0:91d1a7783bb9 545 */
mluis 0:91d1a7783bb9 546 static uint32_t ReceiveDelay1;
mluis 0:91d1a7783bb9 547 static uint32_t ReceiveDelay2;
mluis 0:91d1a7783bb9 548 static uint32_t JoinAcceptDelay1;
mluis 0:91d1a7783bb9 549 static uint32_t JoinAcceptDelay2;
mluis 0:91d1a7783bb9 550
mluis 0:91d1a7783bb9 551 /*!
mluis 0:91d1a7783bb9 552 * LoRaMac reception windows delay
mluis 0:91d1a7783bb9 553 * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
mluis 0:91d1a7783bb9 554 * join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
mluis 0:91d1a7783bb9 555 */
mluis 0:91d1a7783bb9 556 static uint32_t RxWindow1Delay;
mluis 0:91d1a7783bb9 557 static uint32_t RxWindow2Delay;
mluis 0:91d1a7783bb9 558
mluis 0:91d1a7783bb9 559 /*!
mluis 0:91d1a7783bb9 560 * LoRaMac maximum time a reception window stays open
mluis 0:91d1a7783bb9 561 */
mluis 0:91d1a7783bb9 562 static uint32_t MaxRxWindow;
mluis 0:91d1a7783bb9 563
mluis 0:91d1a7783bb9 564 /*!
mluis 0:91d1a7783bb9 565 * Acknowledge timeout timer. Used for packet retransmissions.
mluis 0:91d1a7783bb9 566 */
mluis 0:91d1a7783bb9 567 static TimerEvent_t AckTimeoutTimer;
mluis 0:91d1a7783bb9 568
mluis 0:91d1a7783bb9 569 /*!
mluis 0:91d1a7783bb9 570 * Number of trials to get a frame acknowledged
mluis 0:91d1a7783bb9 571 */
mluis 0:91d1a7783bb9 572 static uint8_t AckTimeoutRetries = 1;
mluis 0:91d1a7783bb9 573
mluis 0:91d1a7783bb9 574 /*!
mluis 0:91d1a7783bb9 575 * Number of trials to get a frame acknowledged
mluis 0:91d1a7783bb9 576 */
mluis 0:91d1a7783bb9 577 static uint8_t AckTimeoutRetriesCounter = 1;
mluis 0:91d1a7783bb9 578
mluis 0:91d1a7783bb9 579 /*!
mluis 0:91d1a7783bb9 580 * Indicates if the AckTimeout timer has expired or not
mluis 0:91d1a7783bb9 581 */
mluis 0:91d1a7783bb9 582 static bool AckTimeoutRetry = false;
mluis 0:91d1a7783bb9 583
mluis 0:91d1a7783bb9 584 /*!
mluis 0:91d1a7783bb9 585 * Last transmission time on air
mluis 0:91d1a7783bb9 586 */
mluis 0:91d1a7783bb9 587 TimerTime_t TxTimeOnAir = 0;
mluis 0:91d1a7783bb9 588
mluis 0:91d1a7783bb9 589 /*!
mluis 2:14a5d6ad92d5 590 * Structure to hold an MCPS indication data.
mluis 2:14a5d6ad92d5 591 */
mluis 2:14a5d6ad92d5 592 static McpsIndication_t McpsIndication;
mluis 2:14a5d6ad92d5 593
mluis 2:14a5d6ad92d5 594 /*!
mluis 2:14a5d6ad92d5 595 * Structure to hold MCPS confirm data.
mluis 2:14a5d6ad92d5 596 */
mluis 2:14a5d6ad92d5 597 static McpsConfirm_t McpsConfirm;
mluis 2:14a5d6ad92d5 598
mluis 2:14a5d6ad92d5 599 /*!
mluis 2:14a5d6ad92d5 600 * Structure to hold MLME confirm data.
mluis 2:14a5d6ad92d5 601 */
mluis 2:14a5d6ad92d5 602 static MlmeConfirm_t MlmeConfirm;
mluis 2:14a5d6ad92d5 603
mluis 2:14a5d6ad92d5 604 /*!
mluis 2:14a5d6ad92d5 605 * Holds the current rx window slot
mluis 2:14a5d6ad92d5 606 */
mluis 2:14a5d6ad92d5 607 static uint8_t RxSlot = 0;
mluis 2:14a5d6ad92d5 608
mluis 2:14a5d6ad92d5 609 /*!
mluis 2:14a5d6ad92d5 610 * LoRaMac tx/rx operation state
mluis 2:14a5d6ad92d5 611 */
mluis 2:14a5d6ad92d5 612 LoRaMacFlags_t LoRaMacFlags;
mluis 2:14a5d6ad92d5 613
snelson 9:ad93de20d720 614 /*!
snelson 9:ad93de20d720 615 * Join Retransmission back-off configuration
snelson 8:4816c8449bf2 616 */
Shaun Nelson 49:8b9e6442a02a 617 LoRaMacRetransmissionDCycle_t JoinReTransmitDCycle[JOIN_NB_RETRANSMISSION_DCYCLES] = {
Shaun Nelson 49:8b9e6442a02a 618 JOIN_RETRANSMISSION_DCYCLE1, JOIN_RETRANSMISSION_DCYCLE2, JOIN_RETRANSMISSION_DCYCLE3};
snelson 8:4816c8449bf2 619
snelson 8:4816c8449bf2 620 /*!
snelson 8:4816c8449bf2 621 * Uptime of the last sent join request
snelson 8:4816c8449bf2 622 */
snelson 8:4816c8449bf2 623 static TimerTime_t LastJoinTxTime;
snelson 8:4816c8449bf2 624
snelson 8:4816c8449bf2 625 /*!
Shaun Nelson 49:8b9e6442a02a 626 * Aggregated join request time on air
snelson 8:4816c8449bf2 627 */
Shaun Nelson 49:8b9e6442a02a 628 static TimerTime_t JoinAggTimeOnAir;
snelson 8:4816c8449bf2 629
mluis 2:14a5d6ad92d5 630 /*!
mluis 2:14a5d6ad92d5 631 * \brief Function to be executed on Radio Tx Done event
mluis 0:91d1a7783bb9 632 */
Shaun Nelson 49:8b9e6442a02a 633 static void OnRadioTxDone(void);
mluis 0:91d1a7783bb9 634
mluis 0:91d1a7783bb9 635 /*!
mluis 3:b9d87593a8ae 636 * \brief This function prepares the MAC to abort the execution of function
mluis 3:b9d87593a8ae 637 * OnRadioRxDone in case of a reception error.
mluis 3:b9d87593a8ae 638 */
Shaun Nelson 49:8b9e6442a02a 639 static void PrepareRxDoneAbort(void);
mluis 3:b9d87593a8ae 640
mluis 3:b9d87593a8ae 641 /*!
mluis 2:14a5d6ad92d5 642 * \brief Function to be executed on Radio Rx Done event
mluis 0:91d1a7783bb9 643 */
Shaun Nelson 49:8b9e6442a02a 644 static void OnRadioRxDone(uint8_t* payload, uint16_t size, int16_t rssi, int8_t snr);
mluis 0:91d1a7783bb9 645
mluis 0:91d1a7783bb9 646 /*!
mluis 2:14a5d6ad92d5 647 * \brief Function executed on Radio Tx Timeout event
mluis 0:91d1a7783bb9 648 */
Shaun Nelson 49:8b9e6442a02a 649 static void OnRadioTxTimeout(void);
mluis 0:91d1a7783bb9 650
mluis 0:91d1a7783bb9 651 /*!
mluis 2:14a5d6ad92d5 652 * \brief Function executed on Radio Rx error event
mluis 0:91d1a7783bb9 653 */
Shaun Nelson 49:8b9e6442a02a 654 static void OnRadioRxError(void);
mluis 0:91d1a7783bb9 655
mluis 0:91d1a7783bb9 656 /*!
mluis 2:14a5d6ad92d5 657 * \brief Function executed on Radio Rx Timeout event
mluis 0:91d1a7783bb9 658 */
Shaun Nelson 49:8b9e6442a02a 659 static void OnRadioRxTimeout(void);
mluis 0:91d1a7783bb9 660
mluis 0:91d1a7783bb9 661 /*!
mluis 2:14a5d6ad92d5 662 * \brief Function executed on Resend Frame timer event.
mluis 0:91d1a7783bb9 663 */
Shaun Nelson 49:8b9e6442a02a 664 static void OnMacStateCheckTimerEvent(void);
mluis 0:91d1a7783bb9 665
mluis 0:91d1a7783bb9 666 /*!
mluis 2:14a5d6ad92d5 667 * \brief Function executed on duty cycle delayed Tx timer event
mluis 0:91d1a7783bb9 668 */
Shaun Nelson 49:8b9e6442a02a 669 static void OnTxDelayedTimerEvent(void);
mluis 0:91d1a7783bb9 670
mluis 0:91d1a7783bb9 671 /*!
mluis 2:14a5d6ad92d5 672 * \brief Function executed on first Rx window timer event
mluis 0:91d1a7783bb9 673 */
Shaun Nelson 49:8b9e6442a02a 674 static void OnRxWindow1TimerEvent(void);
mluis 0:91d1a7783bb9 675
mluis 0:91d1a7783bb9 676 /*!
mluis 2:14a5d6ad92d5 677 * \brief Function executed on second Rx window timer event
mluis 0:91d1a7783bb9 678 */
Shaun Nelson 49:8b9e6442a02a 679 static void OnRxWindow2TimerEvent(void);
mluis 0:91d1a7783bb9 680
mluis 0:91d1a7783bb9 681 /*!
mluis 2:14a5d6ad92d5 682 * \brief Function executed on AckTimeout timer event
mluis 0:91d1a7783bb9 683 */
Shaun Nelson 49:8b9e6442a02a 684 static void OnAckTimeoutTimerEvent(void);
mluis 0:91d1a7783bb9 685
mluis 0:91d1a7783bb9 686 /*!
mluis 2:14a5d6ad92d5 687 * \brief Searches and set the next random available channel
mluis 2:14a5d6ad92d5 688 *
mluis 3:b9d87593a8ae 689 * \param [OUT] Time to wait for the next transmission according to the duty
mluis 3:b9d87593a8ae 690 * cycle.
mluis 3:b9d87593a8ae 691 *
mluis 3:b9d87593a8ae 692 * \retval status Function status [1: OK, 0: Unable to find a channel on the
mluis 3:b9d87593a8ae 693 * current datarate]
mluis 2:14a5d6ad92d5 694 */
Shaun Nelson 49:8b9e6442a02a 695 static bool SetNextChannel(TimerTime_t* time);
mluis 2:14a5d6ad92d5 696
mluis 2:14a5d6ad92d5 697 /*!
mluis 2:14a5d6ad92d5 698 * \brief Sets the network to public or private. Updates the sync byte.
mluis 2:14a5d6ad92d5 699 *
mluis 2:14a5d6ad92d5 700 * \param [IN] enable if true, it enables a public network
mluis 2:14a5d6ad92d5 701 */
Shaun Nelson 49:8b9e6442a02a 702 static void SetPublicNetwork(bool enable);
mluis 2:14a5d6ad92d5 703
mluis 2:14a5d6ad92d5 704 /*!
mluis 2:14a5d6ad92d5 705 * \brief Initializes and opens the reception window
mluis 2:14a5d6ad92d5 706 *
mluis 2:14a5d6ad92d5 707 * \param [IN] freq window channel frequency
mluis 2:14a5d6ad92d5 708 * \param [IN] datarate window channel datarate
mluis 2:14a5d6ad92d5 709 * \param [IN] bandwidth window channel bandwidth
mluis 2:14a5d6ad92d5 710 * \param [IN] timeout window channel timeout
mluis 0:91d1a7783bb9 711 */
Shaun Nelson 49:8b9e6442a02a 712 static void RxWindowSetup(uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout,
Shaun Nelson 49:8b9e6442a02a 713 bool rxContinuous);
mluis 2:14a5d6ad92d5 714
mluis 2:14a5d6ad92d5 715 /*!
shaunkrnelson 16:1e01c8728daa 716 * \brief Verifies if the RX window 2 frequency is in range
shaunkrnelson 16:1e01c8728daa 717 *
shaunkrnelson 16:1e01c8728daa 718 * \param [IN] freq window channel frequency
shaunkrnelson 16:1e01c8728daa 719 *
shaunkrnelson 16:1e01c8728daa 720 * \retval status Function status [1: OK, 0: Frequency not applicable]
shaunkrnelson 16:1e01c8728daa 721 */
Shaun Nelson 49:8b9e6442a02a 722 static bool Rx2FreqInRange(uint32_t freq);
shaunkrnelson 16:1e01c8728daa 723
shaunkrnelson 16:1e01c8728daa 724 /*!
mluis 2:14a5d6ad92d5 725 * \brief Adds a new MAC command to be sent.
mluis 2:14a5d6ad92d5 726 *
mluis 2:14a5d6ad92d5 727 * \Remark MAC layer internal function
mluis 2:14a5d6ad92d5 728 *
mluis 2:14a5d6ad92d5 729 * \param [in] cmd MAC command to be added
mluis 2:14a5d6ad92d5 730 * [MOTE_MAC_LINK_CHECK_REQ,
mluis 2:14a5d6ad92d5 731 * MOTE_MAC_LINK_ADR_ANS,
mluis 2:14a5d6ad92d5 732 * MOTE_MAC_DUTY_CYCLE_ANS,
mluis 2:14a5d6ad92d5 733 * MOTE_MAC_RX2_PARAM_SET_ANS,
mluis 2:14a5d6ad92d5 734 * MOTE_MAC_DEV_STATUS_ANS
mluis 2:14a5d6ad92d5 735 * MOTE_MAC_NEW_CHANNEL_ANS]
mluis 2:14a5d6ad92d5 736 * \param [in] p1 1st parameter ( optional depends on the command )
mluis 2:14a5d6ad92d5 737 * \param [in] p2 2nd parameter ( optional depends on the command )
mluis 2:14a5d6ad92d5 738 *
mluis 2:14a5d6ad92d5 739 * \retval status Function status [0: OK, 1: Unknown command, 2: Buffer full]
mluis 2:14a5d6ad92d5 740 */
Shaun Nelson 49:8b9e6442a02a 741 static LoRaMacStatus_t AddMacCommand(uint8_t cmd, uint8_t p1, uint8_t p2);
mluis 0:91d1a7783bb9 742
mluis 0:91d1a7783bb9 743 /*!
Shaun Nelson 27:cda377b2a41f 744 * \brief Parses the MAC commands which must be repeated.
Shaun Nelson 27:cda377b2a41f 745 *
Shaun Nelson 27:cda377b2a41f 746 * \Remark MAC layer internal function
Shaun Nelson 27:cda377b2a41f 747 *
Shaun Nelson 27:cda377b2a41f 748 * \param [IN] cmdBufIn Buffer which stores the MAC commands to send
Shaun Nelson 27:cda377b2a41f 749 * \param [IN] length Length of the input buffer to parse
Shaun Nelson 27:cda377b2a41f 750 * \param [OUT] cmdBufOut Buffer which stores the MAC commands which must be
Shaun Nelson 27:cda377b2a41f 751 * repeated.
Shaun Nelson 27:cda377b2a41f 752 *
Shaun Nelson 27:cda377b2a41f 753 * \retval Size of the MAC commands to repeat.
Shaun Nelson 27:cda377b2a41f 754 */
Shaun Nelson 49:8b9e6442a02a 755 static uint8_t ParseMacCommandsToRepeat(uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut);
Shaun Nelson 27:cda377b2a41f 756
Shaun Nelson 27:cda377b2a41f 757 /*!
mluis 0:91d1a7783bb9 758 * \brief Validates if the payload fits into the frame, taking the datarate
mluis 0:91d1a7783bb9 759 * into account.
mluis 0:91d1a7783bb9 760 *
mluis 0:91d1a7783bb9 761 * \details Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0
mluis 0:91d1a7783bb9 762 *
mluis 0:91d1a7783bb9 763 * \param lenN Length of the application payload. The length depends on the
mluis 0:91d1a7783bb9 764 * datarate and is region specific
mluis 0:91d1a7783bb9 765 *
mluis 0:91d1a7783bb9 766 * \param datarate Current datarate
mluis 0:91d1a7783bb9 767 *
mluis 2:14a5d6ad92d5 768 * \param fOptsLen Length of the fOpts field
mluis 2:14a5d6ad92d5 769 *
mluis 0:91d1a7783bb9 770 * \retval [false: payload does not fit into the frame, true: payload fits into
mluis 0:91d1a7783bb9 771 * the frame]
mluis 0:91d1a7783bb9 772 */
Shaun Nelson 49:8b9e6442a02a 773 static bool ValidatePayloadLength(uint8_t lenN, int8_t datarate, uint8_t fOptsLen);
mluis 0:91d1a7783bb9 774
mluis 4:37c12dbc8dc7 775 /*!
mluis 4:37c12dbc8dc7 776 * \brief Counts the number of bits in a mask.
mluis 4:37c12dbc8dc7 777 *
mluis 4:37c12dbc8dc7 778 * \param [IN] mask A mask from which the function counts the active bits.
mluis 4:37c12dbc8dc7 779 * \param [IN] nbBits The number of bits to check.
mluis 4:37c12dbc8dc7 780 *
mluis 4:37c12dbc8dc7 781 * \retval Number of enabled bits in the mask.
mluis 4:37c12dbc8dc7 782 */
Shaun Nelson 49:8b9e6442a02a 783 static uint8_t CountBits(uint16_t mask, uint8_t nbBits);
Shaun Nelson 49:8b9e6442a02a 784
Shaun Nelson 49:8b9e6442a02a 785 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
mluis 0:91d1a7783bb9 786 /*!
mluis 0:91d1a7783bb9 787 * \brief Counts the number of enabled 125 kHz channels in the channel mask.
mluis 0:91d1a7783bb9 788 * This function can only be applied to US915 band.
mluis 0:91d1a7783bb9 789 *
mluis 4:37c12dbc8dc7 790 * \param [IN] channelsMask Pointer to the first element of the channel mask
mluis 0:91d1a7783bb9 791 *
mluis 0:91d1a7783bb9 792 * \retval Number of enabled channels in the channel mask
mluis 0:91d1a7783bb9 793 */
Shaun Nelson 49:8b9e6442a02a 794 static uint8_t CountNbEnabled125kHzChannels(uint16_t* channelsMask);
Shaun Nelson 49:8b9e6442a02a 795
Shaun Nelson 49:8b9e6442a02a 796 #if defined(USE_BAND_915_HYBRID)
mluis 4:37c12dbc8dc7 797 /*!
mluis 4:37c12dbc8dc7 798 * \brief Validates the correctness of the channel mask for US915, hybrid mode.
mluis 4:37c12dbc8dc7 799 *
mluis 4:37c12dbc8dc7 800 * \param [IN] mask Block definition to set.
mluis 4:37c12dbc8dc7 801 * \param [OUT] channelsMask Pointer to the first element of the channel mask
mluis 4:37c12dbc8dc7 802 */
Shaun Nelson 49:8b9e6442a02a 803 static void ReenableChannels(uint16_t mask, uint16_t* channelMask);
mluis 4:37c12dbc8dc7 804
mluis 4:37c12dbc8dc7 805 /*!
mluis 4:37c12dbc8dc7 806 * \brief Validates the correctness of the channel mask for US915, hybrid mode.
mluis 4:37c12dbc8dc7 807 *
mluis 4:37c12dbc8dc7 808 * \param [IN] channelsMask Pointer to the first element of the channel mask
mluis 4:37c12dbc8dc7 809 *
mluis 4:37c12dbc8dc7 810 * \retval [true: channel mask correct, false: channel mask not correct]
mluis 4:37c12dbc8dc7 811 */
Shaun Nelson 49:8b9e6442a02a 812 static bool ValidateChannelMask(uint16_t* channelMask);
mluis 4:37c12dbc8dc7 813 #endif
mluis 4:37c12dbc8dc7 814
mluis 0:91d1a7783bb9 815 #endif
mluis 0:91d1a7783bb9 816
mluis 0:91d1a7783bb9 817 /*!
mluis 0:91d1a7783bb9 818 * \brief Limits the Tx power according to the number of enabled channels
mluis 0:91d1a7783bb9 819 *
mluis 0:91d1a7783bb9 820 * \retval Returns the maximum valid tx power
mluis 0:91d1a7783bb9 821 */
Shaun Nelson 49:8b9e6442a02a 822 static int8_t LimitTxPower(int8_t txPower);
mluis 0:91d1a7783bb9 823
mluis 0:91d1a7783bb9 824 /*!
mluis 2:14a5d6ad92d5 825 * \brief Verifies, if a value is in a given range.
mluis 2:14a5d6ad92d5 826 *
mluis 2:14a5d6ad92d5 827 * \param value Value to verify, if it is in range
mluis 2:14a5d6ad92d5 828 *
mluis 2:14a5d6ad92d5 829 * \param min Minimum possible value
mluis 2:14a5d6ad92d5 830 *
mluis 2:14a5d6ad92d5 831 * \param max Maximum possible value
mluis 2:14a5d6ad92d5 832 *
mluis 2:14a5d6ad92d5 833 * \retval Returns the maximum valid tx power
mluis 2:14a5d6ad92d5 834 */
Shaun Nelson 49:8b9e6442a02a 835 static bool ValueInRange(int8_t value, int8_t min, int8_t max);
mluis 2:14a5d6ad92d5 836
mluis 2:14a5d6ad92d5 837 /*!
mluis 2:14a5d6ad92d5 838 * \brief Calculates the next datarate to set, when ADR is on or off
mluis 2:14a5d6ad92d5 839 *
mluis 2:14a5d6ad92d5 840 * \param [IN] adrEnabled Specify whether ADR is on or off
mluis 2:14a5d6ad92d5 841 *
snelson 8:4816c8449bf2 842 * \param [IN] isTx Set to true if called by transmit, set to false if a dry run
mluis 2:14a5d6ad92d5 843 *
mluis 2:14a5d6ad92d5 844 * \param [OUT] datarateOut Reports the datarate which will be used next
mluis 2:14a5d6ad92d5 845 *
snelson 8:4816c8449bf2 846 * \param [OUT] txpowerOut Reports the tx power which will be used next
snelson 8:4816c8449bf2 847 *
mluis 2:14a5d6ad92d5 848 * \retval Returns the state of ADR ack request
mluis 2:14a5d6ad92d5 849 */
Shaun Nelson 49:8b9e6442a02a 850 static bool AdrNextDr(bool adrEnabled, bool isTx, int8_t* datarateOut, int8_t* txpowerOut);
mluis 2:14a5d6ad92d5 851
mluis 2:14a5d6ad92d5 852 /*!
mluis 2:14a5d6ad92d5 853 * \brief Disables channel in a specified channel mask
mluis 2:14a5d6ad92d5 854 *
mluis 2:14a5d6ad92d5 855 * \param [IN] id - Id of the channel
mluis 2:14a5d6ad92d5 856 *
mluis 2:14a5d6ad92d5 857 * \param [IN] mask - Pointer to the channel mask to edit
mluis 0:91d1a7783bb9 858 *
mluis 2:14a5d6ad92d5 859 * \retval [true, if disable was successful, false if not]
mluis 2:14a5d6ad92d5 860 */
Shaun Nelson 49:8b9e6442a02a 861 static bool DisableChannelInMask(uint8_t id, uint16_t* mask);
mluis 2:14a5d6ad92d5 862
mluis 2:14a5d6ad92d5 863 /*!
mluis 2:14a5d6ad92d5 864 * \brief Decodes MAC commands in the fOpts field and in the payload
mluis 2:14a5d6ad92d5 865 */
Shaun Nelson 49:8b9e6442a02a 866 static void ProcessMacCommands(uint8_t* payload, uint8_t macIndex, uint8_t commandsSize,
Shaun Nelson 49:8b9e6442a02a 867 uint8_t snr);
mluis 2:14a5d6ad92d5 868
mluis 2:14a5d6ad92d5 869 /*!
mluis 2:14a5d6ad92d5 870 * \brief LoRaMAC layer generic send frame
mluis 2:14a5d6ad92d5 871 *
mluis 2:14a5d6ad92d5 872 * \param [IN] macHdr MAC header field
mluis 2:14a5d6ad92d5 873 * \param [IN] fPort MAC payload port
mluis 2:14a5d6ad92d5 874 * \param [IN] fBuffer MAC data buffer to be sent
mluis 2:14a5d6ad92d5 875 * \param [IN] fBufferSize MAC data buffer size
mluis 2:14a5d6ad92d5 876 * \retval status Status of the operation.
mluis 2:14a5d6ad92d5 877 */
Shaun Nelson 49:8b9e6442a02a 878 LoRaMacStatus_t Send(LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uint16_t fBufferSize);
mluis 2:14a5d6ad92d5 879
mluis 2:14a5d6ad92d5 880 /*!
mluis 2:14a5d6ad92d5 881 * \brief LoRaMAC layer frame buffer initialization
mluis 2:14a5d6ad92d5 882 *
mluis 2:14a5d6ad92d5 883 * \param [IN] macHdr MAC header field
mluis 2:14a5d6ad92d5 884 * \param [IN] fCtrl MAC frame control field
mluis 2:14a5d6ad92d5 885 * \param [IN] fOpts MAC commands buffer
mluis 2:14a5d6ad92d5 886 * \param [IN] fPort MAC payload port
mluis 2:14a5d6ad92d5 887 * \param [IN] fBuffer MAC data buffer to be sent
mluis 2:14a5d6ad92d5 888 * \param [IN] fBufferSize MAC data buffer size
mluis 2:14a5d6ad92d5 889 * \retval status Status of the operation.
mluis 2:14a5d6ad92d5 890 */
Shaun Nelson 49:8b9e6442a02a 891 LoRaMacStatus_t PrepareFrame(LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort,
Shaun Nelson 49:8b9e6442a02a 892 void* fBuffer, uint16_t fBufferSize);
mluis 2:14a5d6ad92d5 893
mluis 2:14a5d6ad92d5 894 /*
mluis 2:14a5d6ad92d5 895 * \brief Schedules the frame according to the duty cycle
mluis 2:14a5d6ad92d5 896 *
mluis 2:14a5d6ad92d5 897 * \retval Status of the operation
mluis 2:14a5d6ad92d5 898 */
Shaun Nelson 49:8b9e6442a02a 899 static LoRaMacStatus_t ScheduleTx(void);
mluis 2:14a5d6ad92d5 900
mluis 4:37c12dbc8dc7 901 /*
mluis 4:37c12dbc8dc7 902 * \brief Calculates the back-off time for the band of a channel.
mluis 4:37c12dbc8dc7 903 *
mluis 4:37c12dbc8dc7 904 * \param [IN] channel The last Tx channel index
mluis 4:37c12dbc8dc7 905 */
Shaun Nelson 49:8b9e6442a02a 906 static void CalculateBackOff(uint8_t channel);
mluis 4:37c12dbc8dc7 907
mluis 2:14a5d6ad92d5 908 /*!
Shaun Nelson 49:8b9e6442a02a 909 * \brief LoRaMAC layer prepared frame buffer transmission with channel
Shaun Nelson 49:8b9e6442a02a 910 * specification
mluis 2:14a5d6ad92d5 911 *
mluis 2:14a5d6ad92d5 912 * \remark PrepareFrame must be called at least once before calling this
mluis 2:14a5d6ad92d5 913 * function.
mluis 2:14a5d6ad92d5 914 *
mluis 2:14a5d6ad92d5 915 * \param [IN] channel Channel parameters
mluis 2:14a5d6ad92d5 916 * \retval status Status of the operation.
mluis 0:91d1a7783bb9 917 */
Shaun Nelson 49:8b9e6442a02a 918 LoRaMacStatus_t SendFrameOnChannel(ChannelParams_t channel);
Shaun Nelson 49:8b9e6442a02a 919
Shaun Nelson 49:8b9e6442a02a 920 static void OnRadioTxDone(void) {
Shaun Nelson 49:8b9e6442a02a 921 TimerTime_t curTime = TimerGetCurrentTime();
Shaun Nelson 49:8b9e6442a02a 922 if (LoRaMacDeviceClass != CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 923 Radio.Sleep();
Shaun Nelson 49:8b9e6442a02a 924 }
Shaun Nelson 49:8b9e6442a02a 925 else {
Shaun Nelson 49:8b9e6442a02a 926 OnRxWindow2TimerEvent();
Shaun Nelson 49:8b9e6442a02a 927 }
Shaun Nelson 49:8b9e6442a02a 928
Shaun Nelson 49:8b9e6442a02a 929 // Store last Tx channel
Shaun Nelson 49:8b9e6442a02a 930 LastTxChannel = Channel;
Shaun Nelson 49:8b9e6442a02a 931 // Update last tx done time for the current channel
Shaun Nelson 49:8b9e6442a02a 932 Bands[Channels[LastTxChannel].Band].LastTxDoneTime = curTime;
Shaun Nelson 49:8b9e6442a02a 933 // Update Aggregated last tx done time
Shaun Nelson 49:8b9e6442a02a 934 AggregatedLastTxDoneTime = curTime;
Shaun Nelson 49:8b9e6442a02a 935
Shaun Nelson 49:8b9e6442a02a 936 // Update join tx done and time on air
Shaun Nelson 49:8b9e6442a02a 937 if ((LoRaMacFlags.Bits.MlmeReq == 1) && (MlmeConfirm.MlmeRequest == MLME_JOIN)) {
Shaun Nelson 49:8b9e6442a02a 938 JoinAggTimeOnAir += TxTimeOnAir;
Shaun Nelson 49:8b9e6442a02a 939 LastJoinTxTime = curTime;
Shaun Nelson 49:8b9e6442a02a 940 }
Shaun Nelson 49:8b9e6442a02a 941
Shaun Nelson 49:8b9e6442a02a 942 if (IsRxWindowsEnabled == true) {
Shaun Nelson 49:8b9e6442a02a 943 TimerSetValue(&RxWindowTimer1, RxWindow1Delay);
Shaun Nelson 49:8b9e6442a02a 944 TimerStart(&RxWindowTimer1);
Shaun Nelson 49:8b9e6442a02a 945 if (LoRaMacDeviceClass != CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 946 TimerSetValue(&RxWindowTimer2, RxWindow2Delay);
Shaun Nelson 49:8b9e6442a02a 947 TimerStart(&RxWindowTimer2);
mluis 2:14a5d6ad92d5 948 }
Shaun Nelson 49:8b9e6442a02a 949 if ((LoRaMacDeviceClass == CLASS_C) || (NodeAckRequested == true)) {
Shaun Nelson 49:8b9e6442a02a 950 TimerSetValue(&AckTimeoutTimer,
Shaun Nelson 49:8b9e6442a02a 951 RxWindow2Delay + ACK_TIMEOUT + randr(-ACK_TIMEOUT_RND, ACK_TIMEOUT_RND));
Shaun Nelson 49:8b9e6442a02a 952 TimerStart(&AckTimeoutTimer);
mluis 2:14a5d6ad92d5 953 }
Shaun Nelson 49:8b9e6442a02a 954 }
Shaun Nelson 49:8b9e6442a02a 955 else {
Shaun Nelson 49:8b9e6442a02a 956 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 957 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
Shaun Nelson 49:8b9e6442a02a 958
Shaun Nelson 49:8b9e6442a02a 959 if (LoRaMacFlags.Value == 0) {
Shaun Nelson 49:8b9e6442a02a 960 LoRaMacFlags.Bits.McpsReq = 1;
mluis 2:14a5d6ad92d5 961 }
mluis 2:14a5d6ad92d5 962 LoRaMacFlags.Bits.MacDone = 1;
Shaun Nelson 49:8b9e6442a02a 963 }
Shaun Nelson 49:8b9e6442a02a 964
Shaun Nelson 49:8b9e6442a02a 965 if (NodeAckRequested == false) {
Shaun Nelson 49:8b9e6442a02a 966 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 967 ChannelsNbRepCounter++;
Shaun Nelson 49:8b9e6442a02a 968 }
Shaun Nelson 49:8b9e6442a02a 969 }
Shaun Nelson 49:8b9e6442a02a 970
Shaun Nelson 49:8b9e6442a02a 971 static void PrepareRxDoneAbort(void) {
Shaun Nelson 49:8b9e6442a02a 972 LoRaMacState |= MAC_RX_ABORT;
Shaun Nelson 49:8b9e6442a02a 973
Shaun Nelson 49:8b9e6442a02a 974 if (NodeAckRequested) {
Shaun Nelson 49:8b9e6442a02a 975 OnAckTimeoutTimerEvent();
Shaun Nelson 49:8b9e6442a02a 976 }
Shaun Nelson 49:8b9e6442a02a 977
Shaun Nelson 49:8b9e6442a02a 978 if ((RxSlot == 0) && (LoRaMacDeviceClass == CLASS_C)) {
Shaun Nelson 49:8b9e6442a02a 979 OnRxWindow2TimerEvent();
Shaun Nelson 49:8b9e6442a02a 980 }
Shaun Nelson 49:8b9e6442a02a 981
Shaun Nelson 49:8b9e6442a02a 982 LoRaMacFlags.Bits.McpsInd = 1;
Shaun Nelson 49:8b9e6442a02a 983 LoRaMacFlags.Bits.MacDone = 1;
Shaun Nelson 49:8b9e6442a02a 984
Shaun Nelson 49:8b9e6442a02a 985 // Trig OnMacCheckTimerEvent call as soon as possible
Shaun Nelson 49:8b9e6442a02a 986 TimerSetValue(&MacStateCheckTimer, 1000);
Shaun Nelson 49:8b9e6442a02a 987 TimerStart(&MacStateCheckTimer);
mluis 2:14a5d6ad92d5 988 }
mluis 2:14a5d6ad92d5 989
Shaun Nelson 49:8b9e6442a02a 990 static void OnRadioRxDone(uint8_t* payload, uint16_t size, int16_t rssi, int8_t snr) {
Shaun Nelson 49:8b9e6442a02a 991 LoRaMacHeader_t macHdr;
Shaun Nelson 49:8b9e6442a02a 992 LoRaMacFrameCtrl_t fCtrl;
Shaun Nelson 49:8b9e6442a02a 993 bool skipIndication = false;
Shaun Nelson 49:8b9e6442a02a 994
Shaun Nelson 49:8b9e6442a02a 995 uint8_t pktHeaderLen = 0;
Shaun Nelson 49:8b9e6442a02a 996 uint32_t address = 0;
Shaun Nelson 49:8b9e6442a02a 997 uint8_t appPayloadStartIndex = 0;
Shaun Nelson 49:8b9e6442a02a 998 uint8_t port = 0xFF;
Shaun Nelson 49:8b9e6442a02a 999 uint8_t frameLen = 0;
Shaun Nelson 49:8b9e6442a02a 1000 uint32_t mic = 0;
Shaun Nelson 49:8b9e6442a02a 1001 uint32_t micRx = 0;
Shaun Nelson 49:8b9e6442a02a 1002
Shaun Nelson 49:8b9e6442a02a 1003 uint16_t sequenceCounter = 0;
Shaun Nelson 49:8b9e6442a02a 1004 uint16_t sequenceCounterPrev = 0;
Shaun Nelson 49:8b9e6442a02a 1005 uint16_t sequenceCounterDiff = 0;
Shaun Nelson 49:8b9e6442a02a 1006 uint32_t downLinkCounter = 0;
Shaun Nelson 49:8b9e6442a02a 1007
Shaun Nelson 49:8b9e6442a02a 1008 MulticastParams_t* curMulticastParams = NULL;
Shaun Nelson 49:8b9e6442a02a 1009 uint8_t* nwkSKey = LoRaMacNwkSKey;
Shaun Nelson 49:8b9e6442a02a 1010 uint8_t* appSKey = LoRaMacAppSKey;
Shaun Nelson 49:8b9e6442a02a 1011
Shaun Nelson 49:8b9e6442a02a 1012 uint8_t multicast = 0;
Shaun Nelson 49:8b9e6442a02a 1013
Shaun Nelson 49:8b9e6442a02a 1014 bool isMicOk = false;
Shaun Nelson 49:8b9e6442a02a 1015
Shaun Nelson 49:8b9e6442a02a 1016 McpsConfirm.AckReceived = false;
Shaun Nelson 49:8b9e6442a02a 1017 McpsIndication.Rssi = rssi;
Shaun Nelson 49:8b9e6442a02a 1018 McpsIndication.Snr = snr;
Shaun Nelson 49:8b9e6442a02a 1019 McpsIndication.RxSlot = RxSlot;
Shaun Nelson 49:8b9e6442a02a 1020 McpsIndication.Port = 0;
Shaun Nelson 49:8b9e6442a02a 1021 McpsIndication.Multicast = 0;
Shaun Nelson 49:8b9e6442a02a 1022 McpsIndication.FramePending = 0;
Shaun Nelson 49:8b9e6442a02a 1023 McpsIndication.Buffer = NULL;
Shaun Nelson 49:8b9e6442a02a 1024 McpsIndication.BufferSize = 0;
Shaun Nelson 49:8b9e6442a02a 1025 McpsIndication.RxData = false;
Shaun Nelson 49:8b9e6442a02a 1026 McpsIndication.AckReceived = false;
Shaun Nelson 49:8b9e6442a02a 1027 McpsIndication.DownLinkCounter = 0;
Shaun Nelson 49:8b9e6442a02a 1028 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
Shaun Nelson 49:8b9e6442a02a 1029
Shaun Nelson 49:8b9e6442a02a 1030 if (LoRaMacDeviceClass != CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 1031 Radio.Sleep();
Shaun Nelson 49:8b9e6442a02a 1032 }
Shaun Nelson 49:8b9e6442a02a 1033 TimerStop(&RxWindowTimer2);
Shaun Nelson 49:8b9e6442a02a 1034
Shaun Nelson 49:8b9e6442a02a 1035 macHdr.Value = payload[pktHeaderLen++];
Shaun Nelson 49:8b9e6442a02a 1036
Shaun Nelson 49:8b9e6442a02a 1037 switch (macHdr.Bits.MType) {
Shaun Nelson 49:8b9e6442a02a 1038 case FRAME_TYPE_JOIN_ACCEPT:
Shaun Nelson 49:8b9e6442a02a 1039 if (IsLoRaMacNetworkJoined == true) {
Shaun Nelson 49:8b9e6442a02a 1040 break;
Shaun Nelson 49:8b9e6442a02a 1041 }
Shaun Nelson 49:8b9e6442a02a 1042 LoRaMacJoinDecrypt(payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1);
Shaun Nelson 49:8b9e6442a02a 1043
Shaun Nelson 49:8b9e6442a02a 1044 LoRaMacRxPayload[0] = macHdr.Value;
Shaun Nelson 49:8b9e6442a02a 1045
Shaun Nelson 49:8b9e6442a02a 1046 LoRaMacJoinComputeMic(LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic);
Shaun Nelson 49:8b9e6442a02a 1047
Shaun Nelson 49:8b9e6442a02a 1048 micRx |= (uint32_t)LoRaMacRxPayload[size - LORAMAC_MFR_LEN];
Shaun Nelson 49:8b9e6442a02a 1049 micRx |= ((uint32_t)LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8);
Shaun Nelson 49:8b9e6442a02a 1050 micRx |= ((uint32_t)LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16);
Shaun Nelson 49:8b9e6442a02a 1051 micRx |= ((uint32_t)LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24);
Shaun Nelson 49:8b9e6442a02a 1052
Shaun Nelson 49:8b9e6442a02a 1053 if (micRx == mic) {
Shaun Nelson 49:8b9e6442a02a 1054 LoRaMacJoinComputeSKeys(LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce,
Shaun Nelson 49:8b9e6442a02a 1055 LoRaMacNwkSKey, LoRaMacAppSKey);
Shaun Nelson 49:8b9e6442a02a 1056
Shaun Nelson 49:8b9e6442a02a 1057 LoRaMacNetID = (uint32_t)LoRaMacRxPayload[4];
Shaun Nelson 49:8b9e6442a02a 1058 LoRaMacNetID |= ((uint32_t)LoRaMacRxPayload[5] << 8);
Shaun Nelson 49:8b9e6442a02a 1059 LoRaMacNetID |= ((uint32_t)LoRaMacRxPayload[6] << 16);
Shaun Nelson 49:8b9e6442a02a 1060
Shaun Nelson 49:8b9e6442a02a 1061 LoRaMacDevAddr = (uint32_t)LoRaMacRxPayload[7];
Shaun Nelson 49:8b9e6442a02a 1062 LoRaMacDevAddr |= ((uint32_t)LoRaMacRxPayload[8] << 8);
Shaun Nelson 49:8b9e6442a02a 1063 LoRaMacDevAddr |= ((uint32_t)LoRaMacRxPayload[9] << 16);
Shaun Nelson 49:8b9e6442a02a 1064 LoRaMacDevAddr |= ((uint32_t)LoRaMacRxPayload[10] << 24);
Shaun Nelson 49:8b9e6442a02a 1065
Shaun Nelson 49:8b9e6442a02a 1066 // DLSettings
Shaun Nelson 49:8b9e6442a02a 1067 Rx1DrOffset = (LoRaMacRxPayload[11] >> 4) & 0x07;
Shaun Nelson 49:8b9e6442a02a 1068 Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
Shaun Nelson 49:8b9e6442a02a 1069 // RxDelay
Shaun Nelson 49:8b9e6442a02a 1070 ReceiveDelay1 = (LoRaMacRxPayload[12] & 0x0F);
Shaun Nelson 49:8b9e6442a02a 1071 if (ReceiveDelay1 == 0) {
Shaun Nelson 49:8b9e6442a02a 1072 ReceiveDelay1 = 1;
Shaun Nelson 49:8b9e6442a02a 1073 }
Shaun Nelson 49:8b9e6442a02a 1074 ReceiveDelay1 *= 1e6;
Shaun Nelson 49:8b9e6442a02a 1075 ReceiveDelay2 = ReceiveDelay1 + 1e6;
Shaun Nelson 49:8b9e6442a02a 1076
Shaun Nelson 49:8b9e6442a02a 1077 #if !(defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
Shaun Nelson 49:8b9e6442a02a 1078 // CFList
Shaun Nelson 49:8b9e6442a02a 1079 if ((size - 1) > 16) {
Shaun Nelson 49:8b9e6442a02a 1080 ChannelParams_t param;
Shaun Nelson 49:8b9e6442a02a 1081 param.DrRange.Value = (DR_5 << 4) | DR_0;
Shaun Nelson 49:8b9e6442a02a 1082
Shaun Nelson 49:8b9e6442a02a 1083 LoRaMacState |= MAC_TX_CONFIG;
Shaun Nelson 49:8b9e6442a02a 1084 for (uint8_t i = 3, j = 0; i < (5 + 3); i++, j += 3) {
Shaun Nelson 49:8b9e6442a02a 1085 param.Frequency =
Shaun Nelson 49:8b9e6442a02a 1086 ((uint32_t)LoRaMacRxPayload[13 + j] | ((uint32_t)LoRaMacRxPayload[14 + j] << 8) |
Shaun Nelson 49:8b9e6442a02a 1087 ((uint32_t)LoRaMacRxPayload[15 + j] << 16)) *
Shaun Nelson 49:8b9e6442a02a 1088 100;
Shaun Nelson 49:8b9e6442a02a 1089 LoRaMacChannelAdd(i, param);
Shaun Nelson 49:8b9e6442a02a 1090 }
Shaun Nelson 49:8b9e6442a02a 1091 LoRaMacState &= ~MAC_TX_CONFIG;
Shaun Nelson 49:8b9e6442a02a 1092 }
Shaun Nelson 49:8b9e6442a02a 1093 #endif
Shaun Nelson 49:8b9e6442a02a 1094 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 1095 IsLoRaMacNetworkJoined = true;
Shaun Nelson 49:8b9e6442a02a 1096
Shaun Nelson 49:8b9e6442a02a 1097 // Do not change the datarate
Shaun Nelson 49:8b9e6442a02a 1098 // ChannelsDatarate = ChannelsDefaultDatarate;
Shaun Nelson 49:8b9e6442a02a 1099 }
Shaun Nelson 49:8b9e6442a02a 1100 else {
Shaun Nelson 49:8b9e6442a02a 1101 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
Shaun Nelson 49:8b9e6442a02a 1102 }
Shaun Nelson 49:8b9e6442a02a 1103 break;
Shaun Nelson 49:8b9e6442a02a 1104 case FRAME_TYPE_DATA_CONFIRMED_DOWN:
Shaun Nelson 49:8b9e6442a02a 1105 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: {
Shaun Nelson 49:8b9e6442a02a 1106 address = payload[pktHeaderLen++];
Shaun Nelson 49:8b9e6442a02a 1107 address |= ((uint32_t)payload[pktHeaderLen++] << 8);
Shaun Nelson 49:8b9e6442a02a 1108 address |= ((uint32_t)payload[pktHeaderLen++] << 16);
Shaun Nelson 49:8b9e6442a02a 1109 address |= ((uint32_t)payload[pktHeaderLen++] << 24);
Shaun Nelson 49:8b9e6442a02a 1110
Shaun Nelson 49:8b9e6442a02a 1111 if (address != LoRaMacDevAddr) {
Shaun Nelson 49:8b9e6442a02a 1112 curMulticastParams = MulticastChannels;
Shaun Nelson 49:8b9e6442a02a 1113 while (curMulticastParams != NULL) {
Shaun Nelson 49:8b9e6442a02a 1114 if (address == curMulticastParams->Address) {
Shaun Nelson 49:8b9e6442a02a 1115 multicast = 1;
Shaun Nelson 49:8b9e6442a02a 1116 nwkSKey = curMulticastParams->NwkSKey;
Shaun Nelson 49:8b9e6442a02a 1117 appSKey = curMulticastParams->AppSKey;
Shaun Nelson 49:8b9e6442a02a 1118 downLinkCounter = curMulticastParams->DownLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1119 break;
Shaun Nelson 49:8b9e6442a02a 1120 }
Shaun Nelson 49:8b9e6442a02a 1121 curMulticastParams = curMulticastParams->Next;
Shaun Nelson 49:8b9e6442a02a 1122 }
Shaun Nelson 49:8b9e6442a02a 1123 if (multicast == 0) {
Shaun Nelson 49:8b9e6442a02a 1124 // We are not the destination of this frame.
Shaun Nelson 49:8b9e6442a02a 1125 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
Shaun Nelson 49:8b9e6442a02a 1126 PrepareRxDoneAbort();
Shaun Nelson 49:8b9e6442a02a 1127 return;
Shaun Nelson 49:8b9e6442a02a 1128 }
Shaun Nelson 49:8b9e6442a02a 1129 }
Shaun Nelson 49:8b9e6442a02a 1130 else {
Shaun Nelson 49:8b9e6442a02a 1131 multicast = 0;
Shaun Nelson 49:8b9e6442a02a 1132 nwkSKey = LoRaMacNwkSKey;
Shaun Nelson 49:8b9e6442a02a 1133 appSKey = LoRaMacAppSKey;
Shaun Nelson 49:8b9e6442a02a 1134 downLinkCounter = DownLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1135 }
Shaun Nelson 49:8b9e6442a02a 1136
Shaun Nelson 49:8b9e6442a02a 1137 fCtrl.Value = payload[pktHeaderLen++];
Shaun Nelson 49:8b9e6442a02a 1138
Shaun Nelson 49:8b9e6442a02a 1139 sequenceCounter = (uint16_t)payload[pktHeaderLen++];
Shaun Nelson 49:8b9e6442a02a 1140 sequenceCounter |= (uint16_t)payload[pktHeaderLen++] << 8;
Shaun Nelson 49:8b9e6442a02a 1141
Shaun Nelson 49:8b9e6442a02a 1142 appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
Shaun Nelson 49:8b9e6442a02a 1143
Shaun Nelson 49:8b9e6442a02a 1144 micRx |= (uint32_t)payload[size - LORAMAC_MFR_LEN];
Shaun Nelson 49:8b9e6442a02a 1145 micRx |= ((uint32_t)payload[size - LORAMAC_MFR_LEN + 1] << 8);
Shaun Nelson 49:8b9e6442a02a 1146 micRx |= ((uint32_t)payload[size - LORAMAC_MFR_LEN + 2] << 16);
Shaun Nelson 49:8b9e6442a02a 1147 micRx |= ((uint32_t)payload[size - LORAMAC_MFR_LEN + 3] << 24);
Shaun Nelson 49:8b9e6442a02a 1148
Shaun Nelson 49:8b9e6442a02a 1149 sequenceCounterPrev = (uint16_t)downLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1150 sequenceCounterDiff = (sequenceCounter - sequenceCounterPrev);
Shaun Nelson 49:8b9e6442a02a 1151
Shaun Nelson 49:8b9e6442a02a 1152 if (sequenceCounterDiff < (1 << 15)) {
Shaun Nelson 49:8b9e6442a02a 1153 downLinkCounter += sequenceCounterDiff;
Shaun Nelson 49:8b9e6442a02a 1154 LoRaMacComputeMic(payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK,
Shaun Nelson 49:8b9e6442a02a 1155 downLinkCounter, &mic);
Shaun Nelson 49:8b9e6442a02a 1156 if (micRx == mic) {
Shaun Nelson 49:8b9e6442a02a 1157 isMicOk = true;
Shaun Nelson 49:8b9e6442a02a 1158 }
Shaun Nelson 49:8b9e6442a02a 1159 }
Shaun Nelson 49:8b9e6442a02a 1160 else {
Shaun Nelson 49:8b9e6442a02a 1161 // check for sequence roll-over
Shaun Nelson 49:8b9e6442a02a 1162 uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + (int16_t)sequenceCounterDiff;
Shaun Nelson 49:8b9e6442a02a 1163 LoRaMacComputeMic(payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK,
Shaun Nelson 49:8b9e6442a02a 1164 downLinkCounterTmp, &mic);
Shaun Nelson 49:8b9e6442a02a 1165 if (micRx == mic) {
Shaun Nelson 49:8b9e6442a02a 1166 isMicOk = true;
Shaun Nelson 49:8b9e6442a02a 1167 downLinkCounter = downLinkCounterTmp;
Shaun Nelson 49:8b9e6442a02a 1168 }
Shaun Nelson 49:8b9e6442a02a 1169 }
Shaun Nelson 49:8b9e6442a02a 1170
Shaun Nelson 49:8b9e6442a02a 1171 // Check for a the maximum allowed counter difference
Shaun Nelson 49:8b9e6442a02a 1172 if (sequenceCounterDiff >= MAX_FCNT_GAP) {
Shaun Nelson 49:8b9e6442a02a 1173 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
Shaun Nelson 49:8b9e6442a02a 1174 McpsIndication.DownLinkCounter = downLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1175 PrepareRxDoneAbort();
Shaun Nelson 49:8b9e6442a02a 1176 return;
Shaun Nelson 49:8b9e6442a02a 1177 }
Shaun Nelson 49:8b9e6442a02a 1178
Shaun Nelson 49:8b9e6442a02a 1179 if (isMicOk == true) {
Shaun Nelson 49:8b9e6442a02a 1180 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 1181 McpsIndication.Multicast = multicast;
Shaun Nelson 49:8b9e6442a02a 1182 McpsIndication.FramePending = fCtrl.Bits.FPending;
Shaun Nelson 49:8b9e6442a02a 1183 McpsIndication.Buffer = NULL;
Shaun Nelson 49:8b9e6442a02a 1184 McpsIndication.BufferSize = 0;
Shaun Nelson 49:8b9e6442a02a 1185 McpsIndication.DownLinkCounter = downLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1186
Shaun Nelson 49:8b9e6442a02a 1187 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 1188
Shaun Nelson 49:8b9e6442a02a 1189 MacCommandsBufferToRepeatIndex = 0;
Shaun Nelson 49:8b9e6442a02a 1190
Shaun Nelson 49:8b9e6442a02a 1191 // Update 32 bits downlink counter
Shaun Nelson 49:8b9e6442a02a 1192 if (multicast == 1) {
Shaun Nelson 49:8b9e6442a02a 1193 McpsIndication.McpsIndication = MCPS_MULTICAST;
Shaun Nelson 49:8b9e6442a02a 1194
Shaun Nelson 49:8b9e6442a02a 1195 if ((curMulticastParams->DownLinkCounter == downLinkCounter) &&
Shaun Nelson 49:8b9e6442a02a 1196 (curMulticastParams->DownLinkCounter != 0)) {
Shaun Nelson 49:8b9e6442a02a 1197 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
Shaun Nelson 49:8b9e6442a02a 1198 McpsIndication.DownLinkCounter = downLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1199 PrepareRxDoneAbort();
Shaun Nelson 49:8b9e6442a02a 1200 return;
Shaun Nelson 49:8b9e6442a02a 1201 }
Shaun Nelson 49:8b9e6442a02a 1202 curMulticastParams->DownLinkCounter = downLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1203 }
Shaun Nelson 49:8b9e6442a02a 1204 else {
Shaun Nelson 49:8b9e6442a02a 1205 if (macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN) {
Shaun Nelson 49:8b9e6442a02a 1206 SrvAckRequested = true;
Shaun Nelson 49:8b9e6442a02a 1207 McpsIndication.McpsIndication = MCPS_CONFIRMED;
Shaun Nelson 49:8b9e6442a02a 1208
Shaun Nelson 49:8b9e6442a02a 1209 if ((DownLinkCounter == downLinkCounter) && (DownLinkCounter != 0)) {
Shaun Nelson 49:8b9e6442a02a 1210 // Duplicated confirmed downlink. Skip indication.
Shaun Nelson 49:8b9e6442a02a 1211 skipIndication = true;
Shaun Nelson 49:8b9e6442a02a 1212 }
Shaun Nelson 49:8b9e6442a02a 1213 }
Shaun Nelson 49:8b9e6442a02a 1214 else {
Shaun Nelson 49:8b9e6442a02a 1215 SrvAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 1216 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
Shaun Nelson 49:8b9e6442a02a 1217
Shaun Nelson 49:8b9e6442a02a 1218 if ((DownLinkCounter == downLinkCounter) && (DownLinkCounter != 0)) {
Shaun Nelson 49:8b9e6442a02a 1219 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
Shaun Nelson 49:8b9e6442a02a 1220 McpsIndication.DownLinkCounter = downLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1221 PrepareRxDoneAbort();
Shaun Nelson 49:8b9e6442a02a 1222 return;
Shaun Nelson 49:8b9e6442a02a 1223 }
Shaun Nelson 49:8b9e6442a02a 1224 }
Shaun Nelson 49:8b9e6442a02a 1225 DownLinkCounter = downLinkCounter;
Shaun Nelson 49:8b9e6442a02a 1226 }
Shaun Nelson 49:8b9e6442a02a 1227
Shaun Nelson 49:8b9e6442a02a 1228 if (((size - 4) - appPayloadStartIndex) > 0) {
Shaun Nelson 49:8b9e6442a02a 1229 port = payload[appPayloadStartIndex++];
Shaun Nelson 49:8b9e6442a02a 1230 frameLen = (size - 4) - appPayloadStartIndex;
Shaun Nelson 49:8b9e6442a02a 1231
Shaun Nelson 49:8b9e6442a02a 1232 McpsIndication.Port = port;
Shaun Nelson 49:8b9e6442a02a 1233
Shaun Nelson 49:8b9e6442a02a 1234 if (port == 0) {
Shaun Nelson 49:8b9e6442a02a 1235 if (fCtrl.Bits.FOptsLen == 0) {
Shaun Nelson 49:8b9e6442a02a 1236 LoRaMacPayloadDecrypt(payload + appPayloadStartIndex, frameLen, nwkSKey, address,
Shaun Nelson 49:8b9e6442a02a 1237 DOWN_LINK, downLinkCounter, LoRaMacRxPayload);
Shaun Nelson 49:8b9e6442a02a 1238
Shaun Nelson 49:8b9e6442a02a 1239 // Decode frame payload MAC commands
Shaun Nelson 49:8b9e6442a02a 1240 ProcessMacCommands(LoRaMacRxPayload, 0, frameLen, snr);
Shaun Nelson 49:8b9e6442a02a 1241 }
Shaun Nelson 49:8b9e6442a02a 1242 else {
Shaun Nelson 49:8b9e6442a02a 1243 skipIndication = true;
Shaun Nelson 49:8b9e6442a02a 1244 }
Shaun Nelson 49:8b9e6442a02a 1245 }
Shaun Nelson 49:8b9e6442a02a 1246 else {
Shaun Nelson 49:8b9e6442a02a 1247 if (fCtrl.Bits.FOptsLen > 0) {
Shaun Nelson 49:8b9e6442a02a 1248 // Decode Options field MAC commands. Omit the fPort.
Shaun Nelson 49:8b9e6442a02a 1249 ProcessMacCommands(payload, 8, appPayloadStartIndex - 1, snr);
Shaun Nelson 49:8b9e6442a02a 1250 }
Shaun Nelson 49:8b9e6442a02a 1251
Shaun Nelson 49:8b9e6442a02a 1252 LoRaMacPayloadDecrypt(payload + appPayloadStartIndex, frameLen, appSKey, address,
Shaun Nelson 49:8b9e6442a02a 1253 DOWN_LINK, downLinkCounter, LoRaMacRxPayload);
Shaun Nelson 49:8b9e6442a02a 1254
Shaun Nelson 49:8b9e6442a02a 1255 if (skipIndication == false) {
Shaun Nelson 49:8b9e6442a02a 1256 McpsIndication.Buffer = LoRaMacRxPayload;
Shaun Nelson 49:8b9e6442a02a 1257 McpsIndication.BufferSize = frameLen;
Shaun Nelson 49:8b9e6442a02a 1258 McpsIndication.RxData = true;
Shaun Nelson 49:8b9e6442a02a 1259 }
Shaun Nelson 49:8b9e6442a02a 1260 }
Shaun Nelson 49:8b9e6442a02a 1261 }
Shaun Nelson 49:8b9e6442a02a 1262 else {
Shaun Nelson 49:8b9e6442a02a 1263 if (fCtrl.Bits.FOptsLen > 0) {
Shaun Nelson 49:8b9e6442a02a 1264 // Decode Options field MAC commands
Shaun Nelson 49:8b9e6442a02a 1265 ProcessMacCommands(payload, 8, appPayloadStartIndex, snr);
Shaun Nelson 49:8b9e6442a02a 1266 }
Shaun Nelson 49:8b9e6442a02a 1267 }
Shaun Nelson 49:8b9e6442a02a 1268
Shaun Nelson 49:8b9e6442a02a 1269 if (skipIndication == false) {
Shaun Nelson 49:8b9e6442a02a 1270 // Check if the frame is an acknowledgement
Shaun Nelson 49:8b9e6442a02a 1271 if (fCtrl.Bits.Ack == 1) {
Shaun Nelson 49:8b9e6442a02a 1272 McpsConfirm.AckReceived = true;
Shaun Nelson 49:8b9e6442a02a 1273 McpsIndication.AckReceived = true;
Shaun Nelson 49:8b9e6442a02a 1274
Shaun Nelson 49:8b9e6442a02a 1275 // Stop the AckTimeout timer as no more retransmissions
Shaun Nelson 49:8b9e6442a02a 1276 // are needed.
Shaun Nelson 49:8b9e6442a02a 1277 TimerStop(&AckTimeoutTimer);
Shaun Nelson 49:8b9e6442a02a 1278 }
Shaun Nelson 49:8b9e6442a02a 1279 else {
Shaun Nelson 49:8b9e6442a02a 1280 McpsConfirm.AckReceived = false;
Shaun Nelson 49:8b9e6442a02a 1281
Shaun Nelson 49:8b9e6442a02a 1282 if (AckTimeoutRetriesCounter > AckTimeoutRetries) {
Shaun Nelson 49:8b9e6442a02a 1283 // Stop the AckTimeout timer as no more retransmissions
Shaun Nelson 49:8b9e6442a02a 1284 // are needed.
Shaun Nelson 49:8b9e6442a02a 1285 TimerStop(&AckTimeoutTimer);
Shaun Nelson 49:8b9e6442a02a 1286 }
Shaun Nelson 49:8b9e6442a02a 1287 }
Shaun Nelson 49:8b9e6442a02a 1288 LoRaMacFlags.Bits.McpsInd = 1;
Shaun Nelson 49:8b9e6442a02a 1289 }
Shaun Nelson 49:8b9e6442a02a 1290 }
Shaun Nelson 49:8b9e6442a02a 1291 else {
Shaun Nelson 49:8b9e6442a02a 1292 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
Shaun Nelson 49:8b9e6442a02a 1293
Shaun Nelson 49:8b9e6442a02a 1294 PrepareRxDoneAbort();
Shaun Nelson 49:8b9e6442a02a 1295 return;
Shaun Nelson 49:8b9e6442a02a 1296 }
Shaun Nelson 49:8b9e6442a02a 1297 } break;
Shaun Nelson 49:8b9e6442a02a 1298 case FRAME_TYPE_PROPRIETARY: {
Shaun Nelson 49:8b9e6442a02a 1299 memcpy1(LoRaMacRxPayload, &payload[pktHeaderLen], size);
Shaun Nelson 49:8b9e6442a02a 1300
Shaun Nelson 49:8b9e6442a02a 1301 McpsIndication.McpsIndication = MCPS_PROPRIETARY;
Shaun Nelson 49:8b9e6442a02a 1302 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 1303 McpsIndication.Buffer = LoRaMacRxPayload;
Shaun Nelson 49:8b9e6442a02a 1304 McpsIndication.BufferSize = size - pktHeaderLen;
Shaun Nelson 49:8b9e6442a02a 1305
Shaun Nelson 49:8b9e6442a02a 1306 LoRaMacFlags.Bits.McpsInd = 1;
Shaun Nelson 49:8b9e6442a02a 1307 break;
mluis 2:14a5d6ad92d5 1308 }
Shaun Nelson 49:8b9e6442a02a 1309 default:
Shaun Nelson 49:8b9e6442a02a 1310 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
Shaun Nelson 49:8b9e6442a02a 1311 PrepareRxDoneAbort();
Shaun Nelson 49:8b9e6442a02a 1312 break;
Shaun Nelson 49:8b9e6442a02a 1313 }
Shaun Nelson 49:8b9e6442a02a 1314
Shaun Nelson 49:8b9e6442a02a 1315 if ((RxSlot == 0) && (LoRaMacDeviceClass == CLASS_C)) {
Shaun Nelson 49:8b9e6442a02a 1316 OnRxWindow2TimerEvent();
Shaun Nelson 49:8b9e6442a02a 1317 }
Shaun Nelson 49:8b9e6442a02a 1318 LoRaMacFlags.Bits.MacDone = 1;
Shaun Nelson 49:8b9e6442a02a 1319
Shaun Nelson 49:8b9e6442a02a 1320 // Trig OnMacCheckTimerEvent call as soon as possible
Shaun Nelson 49:8b9e6442a02a 1321 TimerSetValue(&MacStateCheckTimer, 1000);
Shaun Nelson 49:8b9e6442a02a 1322 TimerStart(&MacStateCheckTimer);
Shaun Nelson 49:8b9e6442a02a 1323 }
Shaun Nelson 49:8b9e6442a02a 1324
Shaun Nelson 49:8b9e6442a02a 1325 static void OnRadioTxTimeout(void) {
Shaun Nelson 49:8b9e6442a02a 1326 if (LoRaMacDeviceClass != CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 1327 Radio.Sleep();
Shaun Nelson 49:8b9e6442a02a 1328 }
Shaun Nelson 49:8b9e6442a02a 1329 else {
Shaun Nelson 49:8b9e6442a02a 1330 OnRxWindow2TimerEvent();
Shaun Nelson 49:8b9e6442a02a 1331 }
Shaun Nelson 49:8b9e6442a02a 1332
Shaun Nelson 49:8b9e6442a02a 1333 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
Shaun Nelson 49:8b9e6442a02a 1334 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
Shaun Nelson 49:8b9e6442a02a 1335 LoRaMacFlags.Bits.MacDone = 1;
Shaun Nelson 49:8b9e6442a02a 1336 }
Shaun Nelson 49:8b9e6442a02a 1337
Shaun Nelson 49:8b9e6442a02a 1338 static void OnRadioRxError(void) {
Shaun Nelson 49:8b9e6442a02a 1339 if (LoRaMacDeviceClass != CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 1340 Radio.Sleep();
Shaun Nelson 49:8b9e6442a02a 1341 }
Shaun Nelson 49:8b9e6442a02a 1342 else {
Shaun Nelson 49:8b9e6442a02a 1343 OnRxWindow2TimerEvent();
Shaun Nelson 49:8b9e6442a02a 1344 }
Shaun Nelson 49:8b9e6442a02a 1345
Shaun Nelson 49:8b9e6442a02a 1346 if (RxSlot == 1) {
Shaun Nelson 49:8b9e6442a02a 1347 if (NodeAckRequested == true) {
Shaun Nelson 49:8b9e6442a02a 1348 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
mluis 2:14a5d6ad92d5 1349 }
Shaun Nelson 49:8b9e6442a02a 1350 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
mluis 2:14a5d6ad92d5 1351 LoRaMacFlags.Bits.MacDone = 1;
Shaun Nelson 49:8b9e6442a02a 1352 }
Shaun Nelson 49:8b9e6442a02a 1353 }
Shaun Nelson 49:8b9e6442a02a 1354
Shaun Nelson 49:8b9e6442a02a 1355 static void OnRadioRxTimeout(void) {
Shaun Nelson 49:8b9e6442a02a 1356 if (LoRaMacDeviceClass != CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 1357 Radio.Sleep();
Shaun Nelson 49:8b9e6442a02a 1358 }
Shaun Nelson 49:8b9e6442a02a 1359 else {
Shaun Nelson 49:8b9e6442a02a 1360 OnRxWindow2TimerEvent();
Shaun Nelson 49:8b9e6442a02a 1361 }
Shaun Nelson 49:8b9e6442a02a 1362
Shaun Nelson 49:8b9e6442a02a 1363 if (RxSlot == 1) {
Shaun Nelson 49:8b9e6442a02a 1364 if (NodeAckRequested == true) {
Shaun Nelson 49:8b9e6442a02a 1365 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
Shaun Nelson 49:8b9e6442a02a 1366 }
Shaun Nelson 49:8b9e6442a02a 1367 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
Shaun Nelson 49:8b9e6442a02a 1368 LoRaMacFlags.Bits.MacDone = 1;
Shaun Nelson 49:8b9e6442a02a 1369 }
mluis 2:14a5d6ad92d5 1370 }
mluis 2:14a5d6ad92d5 1371
Shaun Nelson 49:8b9e6442a02a 1372 static void OnMacStateCheckTimerEvent(void) {
Shaun Nelson 49:8b9e6442a02a 1373 TimerStop(&MacStateCheckTimer);
Shaun Nelson 49:8b9e6442a02a 1374 bool txTimeout = false;
Shaun Nelson 49:8b9e6442a02a 1375 bool txDone = false;
Shaun Nelson 49:8b9e6442a02a 1376
Shaun Nelson 49:8b9e6442a02a 1377 if (LoRaMacFlags.Bits.MacDone == 1) {
Shaun Nelson 49:8b9e6442a02a 1378 if ((LoRaMacState & MAC_RX_ABORT) == MAC_RX_ABORT) {
Shaun Nelson 49:8b9e6442a02a 1379 LoRaMacState &= ~MAC_RX_ABORT;
Shaun Nelson 49:8b9e6442a02a 1380 LoRaMacState &= ~MAC_TX_RUNNING;
Shaun Nelson 49:8b9e6442a02a 1381 }
Shaun Nelson 49:8b9e6442a02a 1382
Shaun Nelson 49:8b9e6442a02a 1383 if ((LoRaMacFlags.Bits.MlmeReq == 1) || ((LoRaMacFlags.Bits.McpsReq == 1))) {
Shaun Nelson 49:8b9e6442a02a 1384 if ((McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) ||
Shaun Nelson 49:8b9e6442a02a 1385 (MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT)) {
Shaun Nelson 49:8b9e6442a02a 1386 // Stop transmit cycle due to tx timeout.
Shaun Nelson 49:8b9e6442a02a 1387 LoRaMacState &= ~MAC_TX_RUNNING;
Shaun Nelson 49:8b9e6442a02a 1388 McpsConfirm.NbRetries = AckTimeoutRetriesCounter;
Shaun Nelson 49:8b9e6442a02a 1389 McpsConfirm.AckReceived = false;
Shaun Nelson 49:8b9e6442a02a 1390 McpsConfirm.TxTimeOnAir = 0;
Shaun Nelson 49:8b9e6442a02a 1391 txTimeout = true;
Shaun Nelson 49:8b9e6442a02a 1392 }
Shaun Nelson 49:8b9e6442a02a 1393 }
Shaun Nelson 49:8b9e6442a02a 1394
Shaun Nelson 49:8b9e6442a02a 1395 if ((NodeAckRequested == false) && (txTimeout == false)) {
Shaun Nelson 49:8b9e6442a02a 1396 if (LoRaMacFlags.Bits.MlmeReq == 1) {
Shaun Nelson 49:8b9e6442a02a 1397 if (MlmeConfirm.MlmeRequest == MLME_JOIN) {
Shaun Nelson 49:8b9e6442a02a 1398 if (MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_OK) {
Shaun Nelson 49:8b9e6442a02a 1399 UpLinkCounter = 0;
Shaun Nelson 49:8b9e6442a02a 1400 }
Shaun Nelson 49:8b9e6442a02a 1401 // Join messages aren't repeated automatically
Shaun Nelson 49:8b9e6442a02a 1402 ChannelsNbRepCounter = ChannelsNbRep;
Shaun Nelson 49:8b9e6442a02a 1403 }
Shaun Nelson 49:8b9e6442a02a 1404 }
Shaun Nelson 49:8b9e6442a02a 1405 if ((LoRaMacFlags.Bits.MlmeReq == 1) || ((LoRaMacFlags.Bits.McpsReq == 1))) {
Shaun Nelson 49:8b9e6442a02a 1406 if ((ChannelsNbRepCounter >= ChannelsNbRep) || (LoRaMacFlags.Bits.McpsInd == 1)) {
Shaun Nelson 49:8b9e6442a02a 1407 ChannelsNbRepCounter = 0;
Shaun Nelson 49:8b9e6442a02a 1408
Shaun Nelson 49:8b9e6442a02a 1409 txDone = true;
Shaun Nelson 49:8b9e6442a02a 1410 LoRaMacState &= ~MAC_TX_RUNNING;
Shaun Nelson 49:8b9e6442a02a 1411 }
Shaun Nelson 49:8b9e6442a02a 1412 else {
Shaun Nelson 49:8b9e6442a02a 1413 LoRaMacFlags.Bits.MacDone = 0;
Shaun Nelson 49:8b9e6442a02a 1414 // Sends the same frame again
Shaun Nelson 49:8b9e6442a02a 1415 ScheduleTx();
Shaun Nelson 49:8b9e6442a02a 1416 }
Shaun Nelson 49:8b9e6442a02a 1417 }
Shaun Nelson 49:8b9e6442a02a 1418 }
Shaun Nelson 49:8b9e6442a02a 1419
Shaun Nelson 49:8b9e6442a02a 1420 if (LoRaMacFlags.Bits.McpsInd == 1) {
Shaun Nelson 49:8b9e6442a02a 1421 if ((McpsConfirm.AckReceived == true) || (AckTimeoutRetriesCounter > AckTimeoutRetries)) {
Shaun Nelson 49:8b9e6442a02a 1422 AckTimeoutRetry = false;
Shaun Nelson 49:8b9e6442a02a 1423 NodeAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 1424 txDone = true;
Shaun Nelson 49:8b9e6442a02a 1425 McpsConfirm.NbRetries = AckTimeoutRetriesCounter;
Shaun Nelson 49:8b9e6442a02a 1426
Shaun Nelson 49:8b9e6442a02a 1427 LoRaMacState &= ~MAC_TX_RUNNING;
Shaun Nelson 49:8b9e6442a02a 1428 }
mluis 2:14a5d6ad92d5 1429 }
Shaun Nelson 49:8b9e6442a02a 1430
Shaun Nelson 49:8b9e6442a02a 1431 if ((AckTimeoutRetry == true) && ((LoRaMacState & MAC_TX_DELAYED) == 0)) {
Shaun Nelson 49:8b9e6442a02a 1432 AckTimeoutRetry = false;
Shaun Nelson 49:8b9e6442a02a 1433 if ((AckTimeoutRetriesCounter < AckTimeoutRetries) &&
Shaun Nelson 49:8b9e6442a02a 1434 (AckTimeoutRetriesCounter <= MAX_ACK_RETRIES)) {
Shaun Nelson 49:8b9e6442a02a 1435 AckTimeoutRetriesCounter++;
Shaun Nelson 49:8b9e6442a02a 1436
Shaun Nelson 49:8b9e6442a02a 1437 if ((AckTimeoutRetriesCounter % 2) == 1) {
Shaun Nelson 49:8b9e6442a02a 1438 ChannelsDatarate = MAX(ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE);
Shaun Nelson 49:8b9e6442a02a 1439 // Check if new datarate is valid for the Payload length
Shaun Nelson 49:8b9e6442a02a 1440 if (ValidatePayloadLength(LoRaMacBufferPktLen - 13, ChannelsDatarate, 0) == false) {
Shaun Nelson 49:8b9e6442a02a 1441 // If invalid payload length, then revert to previous datarate
Shaun Nelson 49:8b9e6442a02a 1442 ChannelsDatarate++;
Shaun Nelson 49:8b9e6442a02a 1443 }
Shaun Nelson 49:8b9e6442a02a 1444 }
Shaun Nelson 49:8b9e6442a02a 1445 LoRaMacFlags.Bits.MacDone = 0;
Shaun Nelson 49:8b9e6442a02a 1446 // Sends the same frame again
Shaun Nelson 49:8b9e6442a02a 1447 ScheduleTx();
Shaun Nelson 49:8b9e6442a02a 1448 }
Shaun Nelson 49:8b9e6442a02a 1449 else {
Shaun Nelson 49:8b9e6442a02a 1450 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 1451 // Re-enable default channels LC1, LC2, LC3
Shaun Nelson 49:8b9e6442a02a 1452 ChannelsMask[0] = ChannelsMask[0] | (LC(1) + LC(2) + LC(3));
Shaun Nelson 49:8b9e6442a02a 1453 #elif !defined(USE_BAND_915) && !defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 1454 #error "Please define a frequency band in the compiler options."
Shaun Nelson 49:8b9e6442a02a 1455 #endif
Shaun Nelson 49:8b9e6442a02a 1456 LoRaMacState &= ~MAC_TX_RUNNING;
Shaun Nelson 49:8b9e6442a02a 1457
Shaun Nelson 49:8b9e6442a02a 1458 NodeAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 1459 McpsConfirm.AckReceived = false;
Shaun Nelson 49:8b9e6442a02a 1460 McpsConfirm.NbRetries = AckTimeoutRetriesCounter;
Shaun Nelson 49:8b9e6442a02a 1461 txDone = true;
Shaun Nelson 49:8b9e6442a02a 1462 }
Shaun Nelson 49:8b9e6442a02a 1463 }
Shaun Nelson 49:8b9e6442a02a 1464
Shaun Nelson 49:8b9e6442a02a 1465 // Update uplink counter
Shaun Nelson 49:8b9e6442a02a 1466 if ((txDone == true) && (IsUpLinkCounterFixed == false)) {
Shaun Nelson 49:8b9e6442a02a 1467 UpLinkCounter++;
Shaun Nelson 49:8b9e6442a02a 1468
Shaun Nelson 49:8b9e6442a02a 1469 // Reset AdrAckCounter if downlink received
Shaun Nelson 49:8b9e6442a02a 1470 if ((LoRaMacFlags.Bits.McpsInd == 1) || (UpLinkCounter == 1)) {
Shaun Nelson 49:8b9e6442a02a 1471 AdrAckCounter = 0;
Shaun Nelson 49:8b9e6442a02a 1472 }
Shaun Nelson 49:8b9e6442a02a 1473 else {
Shaun Nelson 49:8b9e6442a02a 1474 AdrAckCounter++;
Shaun Nelson 49:8b9e6442a02a 1475 }
Shaun Nelson 49:8b9e6442a02a 1476 }
Shaun Nelson 49:8b9e6442a02a 1477 }
Shaun Nelson 49:8b9e6442a02a 1478 // Handle reception for Class B and Class C
Shaun Nelson 49:8b9e6442a02a 1479 if ((LoRaMacState & MAC_RX) == MAC_RX) {
Shaun Nelson 49:8b9e6442a02a 1480 LoRaMacState &= ~MAC_RX;
Shaun Nelson 49:8b9e6442a02a 1481 }
Shaun Nelson 49:8b9e6442a02a 1482
Shaun Nelson 49:8b9e6442a02a 1483 if (LoRaMacState == MAC_IDLE) {
Shaun Nelson 49:8b9e6442a02a 1484 if (LoRaMacFlags.Bits.McpsReq == 1) {
Shaun Nelson 49:8b9e6442a02a 1485 LoRaMacPrimitives->MacMcpsConfirm(&McpsConfirm);
Shaun Nelson 49:8b9e6442a02a 1486 LoRaMacFlags.Bits.McpsReq = 0;
Shaun Nelson 49:8b9e6442a02a 1487 }
Shaun Nelson 49:8b9e6442a02a 1488
Shaun Nelson 49:8b9e6442a02a 1489 if (LoRaMacFlags.Bits.MlmeReq == 1) {
Shaun Nelson 49:8b9e6442a02a 1490 LoRaMacPrimitives->MacMlmeConfirm(&MlmeConfirm);
Shaun Nelson 49:8b9e6442a02a 1491 LoRaMacFlags.Bits.MlmeReq = 0;
mluis 2:14a5d6ad92d5 1492 }
mluis 2:14a5d6ad92d5 1493
Shaun Nelson 49:8b9e6442a02a 1494 LoRaMacFlags.Bits.MacDone = 0;
Shaun Nelson 49:8b9e6442a02a 1495 }
Shaun Nelson 49:8b9e6442a02a 1496 else {
Shaun Nelson 49:8b9e6442a02a 1497 // Operation not finished restart timer
Shaun Nelson 49:8b9e6442a02a 1498 TimerSetValue(&MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT);
Shaun Nelson 49:8b9e6442a02a 1499 TimerStart(&MacStateCheckTimer);
Shaun Nelson 49:8b9e6442a02a 1500 }
Shaun Nelson 49:8b9e6442a02a 1501
Shaun Nelson 49:8b9e6442a02a 1502 if (LoRaMacFlags.Bits.McpsInd == 1) {
Shaun Nelson 49:8b9e6442a02a 1503 LoRaMacPrimitives->MacMcpsIndication(&McpsIndication);
Shaun Nelson 49:8b9e6442a02a 1504 LoRaMacFlags.Bits.McpsInd = 0;
Shaun Nelson 49:8b9e6442a02a 1505 }
Shaun Nelson 49:8b9e6442a02a 1506 }
Shaun Nelson 49:8b9e6442a02a 1507
Shaun Nelson 49:8b9e6442a02a 1508 static void OnTxDelayedTimerEvent(void) {
Shaun Nelson 49:8b9e6442a02a 1509 TimerStop(&TxDelayedTimer);
Shaun Nelson 49:8b9e6442a02a 1510 LoRaMacState &= ~MAC_TX_DELAYED;
Shaun Nelson 49:8b9e6442a02a 1511
Shaun Nelson 49:8b9e6442a02a 1512 ScheduleTx();
Shaun Nelson 49:8b9e6442a02a 1513 }
Shaun Nelson 49:8b9e6442a02a 1514
Shaun Nelson 49:8b9e6442a02a 1515 static void OnRxWindow1TimerEvent(void) {
Shaun Nelson 49:8b9e6442a02a 1516 uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
Shaun Nelson 49:8b9e6442a02a 1517 int8_t datarate = 0;
Shaun Nelson 49:8b9e6442a02a 1518 uint32_t bandwidth = 0; // LoRa 125 kHz
Shaun Nelson 49:8b9e6442a02a 1519
Shaun Nelson 49:8b9e6442a02a 1520 TimerStop(&RxWindowTimer1);
Shaun Nelson 49:8b9e6442a02a 1521 RxSlot = 0;
Shaun Nelson 49:8b9e6442a02a 1522
Shaun Nelson 49:8b9e6442a02a 1523 if (LoRaMacDeviceClass == CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 1524 Radio.Standby();
Shaun Nelson 49:8b9e6442a02a 1525 }
Shaun Nelson 49:8b9e6442a02a 1526
Shaun Nelson 49:8b9e6442a02a 1527 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 1528 datarate = ChannelsDatarate - Rx1DrOffset;
Shaun Nelson 49:8b9e6442a02a 1529 if (datarate < 0) {
Shaun Nelson 49:8b9e6442a02a 1530 datarate = DR_0;
Shaun Nelson 49:8b9e6442a02a 1531 }
Shaun Nelson 49:8b9e6442a02a 1532
Shaun Nelson 49:8b9e6442a02a 1533 // For higher datarates, we increase the number of symbols generating a Rx
Shaun Nelson 49:8b9e6442a02a 1534 // Timeout
Shaun Nelson 49:8b9e6442a02a 1535 if ((datarate == DR_3) || (datarate == DR_4)) { // DR_4, DR_3
Shaun Nelson 49:8b9e6442a02a 1536 symbTimeout = 8;
Shaun Nelson 49:8b9e6442a02a 1537 }
Shaun Nelson 49:8b9e6442a02a 1538 else if (datarate == DR_5) {
Shaun Nelson 49:8b9e6442a02a 1539 symbTimeout = 10;
Shaun Nelson 49:8b9e6442a02a 1540 }
Shaun Nelson 49:8b9e6442a02a 1541 else if (datarate == DR_6) { // LoRa 250 kHz
Shaun Nelson 49:8b9e6442a02a 1542 bandwidth = 1;
Shaun Nelson 49:8b9e6442a02a 1543 symbTimeout = 14;
Shaun Nelson 49:8b9e6442a02a 1544 }
Shaun Nelson 49:8b9e6442a02a 1545 RxWindowSetup(Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false);
Shaun Nelson 49:8b9e6442a02a 1546 #elif (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
Shaun Nelson 49:8b9e6442a02a 1547 datarate = datarateOffsets[ChannelsDatarate][Rx1DrOffset];
Shaun Nelson 49:8b9e6442a02a 1548 if (datarate < 0) {
Shaun Nelson 49:8b9e6442a02a 1549 datarate = DR_0;
Shaun Nelson 49:8b9e6442a02a 1550 }
Shaun Nelson 49:8b9e6442a02a 1551 // For higher datarates, we increase the number of symbols generating a Rx
Shaun Nelson 49:8b9e6442a02a 1552 // Timeout
Shaun Nelson 49:8b9e6442a02a 1553
Shaun Nelson 49:8b9e6442a02a 1554 symbTimeout = 10;
Shaun Nelson 49:8b9e6442a02a 1555 // For low SF, we increase the number of symbols generating a Rx Timeout
Shaun Nelson 49:8b9e6442a02a 1556 switch (datarate) {
Shaun Nelson 49:8b9e6442a02a 1557 case DR_0:
Shaun Nelson 49:8b9e6442a02a 1558 case DR_8:
Shaun Nelson 49:8b9e6442a02a 1559 case DR_9:
Shaun Nelson 49:8b9e6442a02a 1560 case DR_10:
Shaun Nelson 49:8b9e6442a02a 1561 symbTimeout += 5;
Shaun Nelson 49:8b9e6442a02a 1562 break;
Shaun Nelson 49:8b9e6442a02a 1563 case DR_1:
Shaun Nelson 49:8b9e6442a02a 1564 case DR_11:
Shaun Nelson 49:8b9e6442a02a 1565 symbTimeout += 8;
Shaun Nelson 49:8b9e6442a02a 1566 break;
Shaun Nelson 49:8b9e6442a02a 1567 case DR_2:
Shaun Nelson 49:8b9e6442a02a 1568 case DR_4:
Shaun Nelson 49:8b9e6442a02a 1569 case DR_12:
Shaun Nelson 49:8b9e6442a02a 1570 symbTimeout += 9;
Shaun Nelson 49:8b9e6442a02a 1571 break;
Shaun Nelson 49:8b9e6442a02a 1572 case DR_3:
Shaun Nelson 49:8b9e6442a02a 1573 case DR_13:
Shaun Nelson 49:8b9e6442a02a 1574 symbTimeout += 10;
Shaun Nelson 49:8b9e6442a02a 1575 break;
Shaun Nelson 49:8b9e6442a02a 1576 default:
Shaun Nelson 49:8b9e6442a02a 1577 symbTimeout += 5;
Shaun Nelson 49:8b9e6442a02a 1578 break;
Shaun Nelson 49:8b9e6442a02a 1579 }
Shaun Nelson 49:8b9e6442a02a 1580
Shaun Nelson 49:8b9e6442a02a 1581 if (datarate >= DR_4) { // LoRa 500 kHz
Shaun Nelson 49:8b9e6442a02a 1582 bandwidth = 2;
Shaun Nelson 49:8b9e6442a02a 1583 }
Shaun Nelson 49:8b9e6442a02a 1584 RxWindowSetup(923.3e6 + (Channel % 8) * 600e3, datarate, bandwidth, symbTimeout, false);
Shaun Nelson 49:8b9e6442a02a 1585 #else
Shaun Nelson 49:8b9e6442a02a 1586 #error "Please define a frequency band in the compiler options."
Shaun Nelson 49:8b9e6442a02a 1587 #endif
Shaun Nelson 49:8b9e6442a02a 1588 }
Shaun Nelson 49:8b9e6442a02a 1589
Shaun Nelson 49:8b9e6442a02a 1590 static void OnRxWindow2TimerEvent(void) {
Shaun Nelson 49:8b9e6442a02a 1591 uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
Shaun Nelson 49:8b9e6442a02a 1592 uint32_t bandwidth = 0; // LoRa 125 kHz
Shaun Nelson 49:8b9e6442a02a 1593
Shaun Nelson 49:8b9e6442a02a 1594 TimerStop(&RxWindowTimer2);
Shaun Nelson 49:8b9e6442a02a 1595 RxSlot = 1;
Shaun Nelson 49:8b9e6442a02a 1596
Shaun Nelson 49:8b9e6442a02a 1597 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 1598 // For higher datarates, we increase the number of symbols generating a Rx
Shaun Nelson 49:8b9e6442a02a 1599 // Timeout
Shaun Nelson 49:8b9e6442a02a 1600 if ((Rx2Channel.Datarate == DR_3) || (Rx2Channel.Datarate == DR_4)) { // DR_4, DR_3
Shaun Nelson 49:8b9e6442a02a 1601 symbTimeout = 8;
Shaun Nelson 49:8b9e6442a02a 1602 }
Shaun Nelson 49:8b9e6442a02a 1603 else if (Rx2Channel.Datarate == DR_5) {
Shaun Nelson 49:8b9e6442a02a 1604 symbTimeout = 10;
Shaun Nelson 49:8b9e6442a02a 1605 }
Shaun Nelson 49:8b9e6442a02a 1606 else if (Rx2Channel.Datarate == DR_6) { // LoRa 250 kHz
Shaun Nelson 49:8b9e6442a02a 1607 bandwidth = 1;
Shaun Nelson 49:8b9e6442a02a 1608 symbTimeout = 14;
Shaun Nelson 49:8b9e6442a02a 1609 }
Shaun Nelson 49:8b9e6442a02a 1610 #elif (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
Shaun Nelson 49:8b9e6442a02a 1611 // For higher datarates, we increase the number of symbols generating a Rx
Shaun Nelson 49:8b9e6442a02a 1612 // Timeout
Shaun Nelson 49:8b9e6442a02a 1613 switch (Rx2Channel.Datarate) {
Shaun Nelson 49:8b9e6442a02a 1614 case DR_0: // SF10 - BW125
Shaun Nelson 49:8b9e6442a02a 1615 symbTimeout = 5;
Shaun Nelson 49:8b9e6442a02a 1616 break;
Shaun Nelson 49:8b9e6442a02a 1617
Shaun Nelson 49:8b9e6442a02a 1618 case DR_1: // SF9 - BW125
Shaun Nelson 49:8b9e6442a02a 1619 case DR_2: // SF8 - BW125
Shaun Nelson 49:8b9e6442a02a 1620 case DR_8: // SF12 - BW500
Shaun Nelson 49:8b9e6442a02a 1621 case DR_9: // SF11 - BW500
Shaun Nelson 49:8b9e6442a02a 1622 case DR_10: // SF10 - BW500
Shaun Nelson 49:8b9e6442a02a 1623 symbTimeout = 8;
Shaun Nelson 49:8b9e6442a02a 1624 break;
Shaun Nelson 49:8b9e6442a02a 1625
Shaun Nelson 49:8b9e6442a02a 1626 case DR_3: // SF7 - BW125
Shaun Nelson 49:8b9e6442a02a 1627 case DR_11: // SF9 - BW500
Shaun Nelson 49:8b9e6442a02a 1628 symbTimeout = 10;
Shaun Nelson 49:8b9e6442a02a 1629 break;
Shaun Nelson 49:8b9e6442a02a 1630
Shaun Nelson 49:8b9e6442a02a 1631 case DR_4: // SF8 - BW500
Shaun Nelson 49:8b9e6442a02a 1632 case DR_12: // SF8 - BW500
Shaun Nelson 49:8b9e6442a02a 1633 symbTimeout = 14;
Shaun Nelson 49:8b9e6442a02a 1634 break;
Shaun Nelson 49:8b9e6442a02a 1635
Shaun Nelson 49:8b9e6442a02a 1636 case DR_13: // SF7 - BW500
Shaun Nelson 49:8b9e6442a02a 1637 symbTimeout = 16;
Shaun Nelson 49:8b9e6442a02a 1638 break;
Shaun Nelson 49:8b9e6442a02a 1639 default:
Shaun Nelson 49:8b9e6442a02a 1640 break;
Shaun Nelson 49:8b9e6442a02a 1641 }
Shaun Nelson 49:8b9e6442a02a 1642 if (Rx2Channel.Datarate >= DR_4) { // LoRa 500 kHz
Shaun Nelson 49:8b9e6442a02a 1643 bandwidth = 2;
Shaun Nelson 49:8b9e6442a02a 1644 }
Shaun Nelson 49:8b9e6442a02a 1645 #else
Shaun Nelson 49:8b9e6442a02a 1646 #error "Please define a frequency band in the compiler options."
Shaun Nelson 49:8b9e6442a02a 1647 #endif
Shaun Nelson 49:8b9e6442a02a 1648 if (LoRaMacDeviceClass != CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 1649 RxWindowSetup(Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, false);
Shaun Nelson 49:8b9e6442a02a 1650 }
Shaun Nelson 49:8b9e6442a02a 1651 else {
Shaun Nelson 49:8b9e6442a02a 1652 RxWindowSetup(Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, true);
Shaun Nelson 49:8b9e6442a02a 1653 }
Shaun Nelson 49:8b9e6442a02a 1654 }
Shaun Nelson 49:8b9e6442a02a 1655
Shaun Nelson 49:8b9e6442a02a 1656 static void OnAckTimeoutTimerEvent(void) {
Shaun Nelson 49:8b9e6442a02a 1657 TimerStop(&AckTimeoutTimer);
Shaun Nelson 49:8b9e6442a02a 1658
Shaun Nelson 49:8b9e6442a02a 1659 if (NodeAckRequested == true) {
Shaun Nelson 49:8b9e6442a02a 1660 AckTimeoutRetry = true;
Shaun Nelson 49:8b9e6442a02a 1661 LoRaMacState &= ~MAC_ACK_REQ;
Shaun Nelson 49:8b9e6442a02a 1662 }
Shaun Nelson 49:8b9e6442a02a 1663 if (LoRaMacDeviceClass == CLASS_C) {
Shaun Nelson 49:8b9e6442a02a 1664 LoRaMacFlags.Bits.MacDone = 1;
Shaun Nelson 49:8b9e6442a02a 1665 }
Shaun Nelson 49:8b9e6442a02a 1666 }
Shaun Nelson 49:8b9e6442a02a 1667
Shaun Nelson 49:8b9e6442a02a 1668 #if defined(USE_BAND_915)
Shaun Nelson 49:8b9e6442a02a 1669 uint8_t GetNextJoinChannel(uint8_t* enabledChannels, uint8_t nbEnabledChannels) {
Shaun Nelson 49:8b9e6442a02a 1670 int8_t channel = -1;
Shaun Nelson 49:8b9e6442a02a 1671 uint8_t block;
Shaun Nelson 49:8b9e6442a02a 1672 uint8_t i;
Shaun Nelson 49:8b9e6442a02a 1673
Shaun Nelson 49:8b9e6442a02a 1674 // Use 125KHz channel
Shaun Nelson 49:8b9e6442a02a 1675 if (ChannelsDatarate < DR_4) {
Shaun Nelson 49:8b9e6442a02a 1676 block = JoinBlock[NextJoinBlock];
Shaun Nelson 49:8b9e6442a02a 1677 NextJoinBlock = (NextJoinBlock + 1) % 8;
Shaun Nelson 49:8b9e6442a02a 1678
Shaun Nelson 49:8b9e6442a02a 1679 // If next block is greater than max block then randomly select the next
Shaun Nelson 49:8b9e6442a02a 1680 // block
Shaun Nelson 49:8b9e6442a02a 1681 if (block >= 8)
Shaun Nelson 49:8b9e6442a02a 1682 block = randr(0, 7);
Shaun Nelson 49:8b9e6442a02a 1683
Shaun Nelson 49:8b9e6442a02a 1684 // Start search for next join channel at the selected block
Shaun Nelson 49:8b9e6442a02a 1685 for (i = 0; (i < 8) && (channel == -1); i++) {
Shaun Nelson 49:8b9e6442a02a 1686 uint8_t curBlock = (block + i) % 8;
Shaun Nelson 49:8b9e6442a02a 1687 uint8_t chMask;
Shaun Nelson 49:8b9e6442a02a 1688
Shaun Nelson 49:8b9e6442a02a 1689 // Cycle through all blocks before using a previously used block
Shaun Nelson 49:8b9e6442a02a 1690 if (((JoinBlocksRemaining & (1 << curBlock)) != 0)) {
Shaun Nelson 49:8b9e6442a02a 1691 chMask = (ChannelsMaskRemaining[curBlock / 2] >> (curBlock & 1 ? 8 : 0)) & 0xff;
Shaun Nelson 49:8b9e6442a02a 1692 if (chMask != 0) {
Shaun Nelson 49:8b9e6442a02a 1693 channel = randr(0, 7);
Shaun Nelson 49:8b9e6442a02a 1694 for (uint8_t i = 0; (i < 8); i++) {
Shaun Nelson 49:8b9e6442a02a 1695 if ((chMask & (1 << channel)) != 0) {
Shaun Nelson 49:8b9e6442a02a 1696 uint16_t chMaskTmp = (1 << channel);
Shaun Nelson 49:8b9e6442a02a 1697 chMaskTmp = chMaskTmp << (curBlock & 1 ? 8 : 0);
Shaun Nelson 49:8b9e6442a02a 1698 channel = channel + (curBlock * 8);
Shaun Nelson 49:8b9e6442a02a 1699 JoinBlocksRemaining &= ~(1 << curBlock);
Shaun Nelson 49:8b9e6442a02a 1700 ChannelsMaskRemaining[curBlock / 2] &= ~chMaskTmp;
Shaun Nelson 49:8b9e6442a02a 1701 if ((JoinBlocksRemaining == 0)) {
Shaun Nelson 49:8b9e6442a02a 1702 JoinBlocksRemaining = 0xFF;
Shaun Nelson 49:8b9e6442a02a 1703 }
Shaun Nelson 49:8b9e6442a02a 1704 break;
Shaun Nelson 49:8b9e6442a02a 1705 }
Shaun Nelson 49:8b9e6442a02a 1706 else {
Shaun Nelson 49:8b9e6442a02a 1707 channel = (channel + 1) % 8;
Shaun Nelson 49:8b9e6442a02a 1708 }
Shaun Nelson 49:8b9e6442a02a 1709 }
mluis 2:14a5d6ad92d5 1710 }
Shaun Nelson 49:8b9e6442a02a 1711 }
Shaun Nelson 49:8b9e6442a02a 1712 }
Shaun Nelson 49:8b9e6442a02a 1713
Shaun Nelson 49:8b9e6442a02a 1714 // No next channel case should never happen since ScheduleTx has already
Shaun Nelson 49:8b9e6442a02a 1715 // checked for at least one enabled channel and if none re-enabled all
Shaun Nelson 49:8b9e6442a02a 1716 // channels.
Shaun Nelson 49:8b9e6442a02a 1717 // But if we find ourselves without a channel then randomly select one
Shaun Nelson 49:8b9e6442a02a 1718 if (i >= 8) {
Shaun Nelson 49:8b9e6442a02a 1719 channel = randr(0, 63);
mluis 2:14a5d6ad92d5 1720 }
Shaun Nelson 49:8b9e6442a02a 1721 }
Shaun Nelson 49:8b9e6442a02a 1722 // Use 500 KHz channel
Shaun Nelson 49:8b9e6442a02a 1723 else {
Shaun Nelson 49:8b9e6442a02a 1724 channel = randr(0, 7);
Shaun Nelson 49:8b9e6442a02a 1725 for (i = 0; i < 8; i++) {
Shaun Nelson 49:8b9e6442a02a 1726 uint8_t curChannel = (channel + i) % 8;
Shaun Nelson 49:8b9e6442a02a 1727
Shaun Nelson 49:8b9e6442a02a 1728 if (((Join500KHzRemaining & (1 << curChannel)) != 0)) {
Shaun Nelson 49:8b9e6442a02a 1729 Join500KHzRemaining &= ~(1 << curChannel);
Shaun Nelson 49:8b9e6442a02a 1730 channel = 64 + curChannel;
Shaun Nelson 49:8b9e6442a02a 1731 if (Join500KHzRemaining == 0) {
Shaun Nelson 49:8b9e6442a02a 1732 Join500KHzRemaining = 0xFF;
Shaun Nelson 49:8b9e6442a02a 1733 }
Shaun Nelson 49:8b9e6442a02a 1734 break;
Shaun Nelson 49:8b9e6442a02a 1735 }
Shaun Nelson 49:8b9e6442a02a 1736 }
Shaun Nelson 49:8b9e6442a02a 1737 }
Shaun Nelson 49:8b9e6442a02a 1738
Shaun Nelson 49:8b9e6442a02a 1739 for (i = 0; i < nbEnabledChannels; i++) {
Shaun Nelson 49:8b9e6442a02a 1740 if (enabledChannels[i] == channel)
Shaun Nelson 49:8b9e6442a02a 1741 break;
Shaun Nelson 49:8b9e6442a02a 1742 }
Shaun Nelson 49:8b9e6442a02a 1743
Shaun Nelson 49:8b9e6442a02a 1744 if (i == nbEnabledChannels) {
Shaun Nelson 49:8b9e6442a02a 1745 channel = enabledChannels[randr(0, nbEnabledChannels - 1)];
Shaun Nelson 49:8b9e6442a02a 1746 }
Shaun Nelson 49:8b9e6442a02a 1747
Shaun Nelson 49:8b9e6442a02a 1748 LastJoinBlock = channel / 8;
Shaun Nelson 49:8b9e6442a02a 1749
Shaun Nelson 49:8b9e6442a02a 1750 return channel;
mluis 2:14a5d6ad92d5 1751 }
Shaun Nelson 49:8b9e6442a02a 1752 #endif
Shaun Nelson 49:8b9e6442a02a 1753
Shaun Nelson 49:8b9e6442a02a 1754 static bool SetNextChannel(TimerTime_t* time) {
Shaun Nelson 49:8b9e6442a02a 1755 uint8_t nbEnabledChannels = 0;
Shaun Nelson 49:8b9e6442a02a 1756 uint8_t delayTx = 0;
Shaun Nelson 49:8b9e6442a02a 1757 uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
Shaun Nelson 49:8b9e6442a02a 1758 TimerTime_t nextTxDelay = (TimerTime_t)(-1);
Shaun Nelson 49:8b9e6442a02a 1759
Shaun Nelson 49:8b9e6442a02a 1760 memset1(enabledChannels, 0, LORA_MAX_NB_CHANNELS);
Shaun Nelson 49:8b9e6442a02a 1761
Shaun Nelson 49:8b9e6442a02a 1762 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 1763 if (CountNbEnabled125kHzChannels(ChannelsMaskRemaining) == 0) { // Restore default channels
Shaun Nelson 49:8b9e6442a02a 1764 memcpy1((uint8_t*)ChannelsMaskRemaining, (uint8_t*)ChannelsMask, 8);
Shaun Nelson 49:8b9e6442a02a 1765 }
Shaun Nelson 49:8b9e6442a02a 1766 if ((ChannelsDatarate >= DR_4) &&
Shaun Nelson 49:8b9e6442a02a 1767 ((ChannelsMaskRemaining[4] & 0x00FF) == 0)) { // Make sure, that the channels are activated
Shaun Nelson 49:8b9e6442a02a 1768 ChannelsMaskRemaining[4] = ChannelsMask[4];
Shaun Nelson 49:8b9e6442a02a 1769 }
Shaun Nelson 49:8b9e6442a02a 1770 #else
Shaun Nelson 49:8b9e6442a02a 1771 if (CountBits(ChannelsMask[0], 16) == 0) {
Shaun Nelson 49:8b9e6442a02a 1772 // Re-enable default channels, if no channel is enabled
Shaun Nelson 49:8b9e6442a02a 1773 ChannelsMask[0] = ChannelsMask[0] | (LC(1) + LC(2) + LC(3));
Shaun Nelson 49:8b9e6442a02a 1774 }
Shaun Nelson 49:8b9e6442a02a 1775 #endif
Shaun Nelson 49:8b9e6442a02a 1776
Shaun Nelson 49:8b9e6442a02a 1777 // Update Aggregated duty cycle
Shaun Nelson 49:8b9e6442a02a 1778 if (AggregatedTimeOff <= TimerGetElapsedTime(AggregatedLastTxDoneTime)) {
Shaun Nelson 49:8b9e6442a02a 1779 AggregatedTimeOff = 0;
Shaun Nelson 49:8b9e6442a02a 1780
Shaun Nelson 49:8b9e6442a02a 1781 // Update bands Time OFF
Shaun Nelson 49:8b9e6442a02a 1782 for (uint8_t i = 0; i < LORA_MAX_NB_BANDS; i++) {
Shaun Nelson 49:8b9e6442a02a 1783 if (DutyCycleOn == true) {
Shaun Nelson 49:8b9e6442a02a 1784 if (Bands[i].TimeOff <= TimerGetElapsedTime(Bands[i].LastTxDoneTime)) {
Shaun Nelson 49:8b9e6442a02a 1785 Bands[i].TimeOff = 0;
Shaun Nelson 49:8b9e6442a02a 1786 }
Shaun Nelson 49:8b9e6442a02a 1787 if (Bands[i].TimeOff != 0) {
Shaun Nelson 49:8b9e6442a02a 1788 nextTxDelay =
Shaun Nelson 49:8b9e6442a02a 1789 MIN(Bands[i].TimeOff - TimerGetElapsedTime(Bands[i].LastTxDoneTime), nextTxDelay);
Shaun Nelson 49:8b9e6442a02a 1790 }
Shaun Nelson 49:8b9e6442a02a 1791 }
Shaun Nelson 49:8b9e6442a02a 1792 else {
Shaun Nelson 49:8b9e6442a02a 1793 nextTxDelay = 0;
Shaun Nelson 49:8b9e6442a02a 1794 Bands[i].TimeOff = 0;
Shaun Nelson 49:8b9e6442a02a 1795 }
Shaun Nelson 49:8b9e6442a02a 1796 }
Shaun Nelson 49:8b9e6442a02a 1797
Shaun Nelson 49:8b9e6442a02a 1798 // Search how many channels are enabled
Shaun Nelson 49:8b9e6442a02a 1799 for (uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++) {
Shaun Nelson 49:8b9e6442a02a 1800 for (uint8_t j = 0; j < 16; j++) {
Shaun Nelson 49:8b9e6442a02a 1801 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 1802 if ((ChannelsMaskRemaining[k] & (1 << j)) != 0)
Shaun Nelson 49:8b9e6442a02a 1803 #else
Shaun Nelson 49:8b9e6442a02a 1804 if ((ChannelsMask[k] & (1 << j)) != 0)
Shaun Nelson 49:8b9e6442a02a 1805 #endif
Shaun Nelson 49:8b9e6442a02a 1806 {
Shaun Nelson 49:8b9e6442a02a 1807 if (Channels[i + j].Frequency == 0) { // Check if the channel is enabled
Shaun Nelson 49:8b9e6442a02a 1808 continue;
Shaun Nelson 49:8b9e6442a02a 1809 }
Shaun Nelson 49:8b9e6442a02a 1810 #if defined(USE_BAND_868) || defined(USE_BAND_433) || defined(USE_BAND_780)
Shaun Nelson 49:8b9e6442a02a 1811 if (IsLoRaMacNetworkJoined == false) {
Shaun Nelson 49:8b9e6442a02a 1812 if ((JOIN_CHANNELS & (1 << j)) == 0) {
Shaun Nelson 49:8b9e6442a02a 1813 continue;
Shaun Nelson 49:8b9e6442a02a 1814 }
Shaun Nelson 49:8b9e6442a02a 1815 }
Shaun Nelson 49:8b9e6442a02a 1816 #endif
Shaun Nelson 49:8b9e6442a02a 1817 if (((Channels[i + j].DrRange.Fields.Min <= ChannelsDatarate) &&
Shaun Nelson 49:8b9e6442a02a 1818 (ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max)) ==
Shaun Nelson 49:8b9e6442a02a 1819 false) { // Check if the current channel selection supports the
Shaun Nelson 49:8b9e6442a02a 1820 // given datarate
Shaun Nelson 49:8b9e6442a02a 1821 continue;
Shaun Nelson 49:8b9e6442a02a 1822 }
Shaun Nelson 49:8b9e6442a02a 1823 if (Bands[Channels[i + j].Band].TimeOff >
Shaun Nelson 49:8b9e6442a02a 1824 0) { // Check if the band is available for transmission
Shaun Nelson 49:8b9e6442a02a 1825 delayTx++;
Shaun Nelson 49:8b9e6442a02a 1826 continue;
Shaun Nelson 49:8b9e6442a02a 1827 }
Shaun Nelson 49:8b9e6442a02a 1828 enabledChannels[nbEnabledChannels++] = i + j;
Shaun Nelson 49:8b9e6442a02a 1829 }
Shaun Nelson 49:8b9e6442a02a 1830 }
Shaun Nelson 49:8b9e6442a02a 1831 }
Shaun Nelson 49:8b9e6442a02a 1832 }
Shaun Nelson 49:8b9e6442a02a 1833 else {
Shaun Nelson 49:8b9e6442a02a 1834 delayTx++;
Shaun Nelson 49:8b9e6442a02a 1835 nextTxDelay = AggregatedTimeOff - TimerGetElapsedTime(AggregatedLastTxDoneTime);
Shaun Nelson 49:8b9e6442a02a 1836 }
Shaun Nelson 49:8b9e6442a02a 1837
Shaun Nelson 49:8b9e6442a02a 1838 if (nbEnabledChannels > 0) {
Shaun Nelson 49:8b9e6442a02a 1839 #if defined(USE_BAND_915)
Shaun Nelson 49:8b9e6442a02a 1840 if (IsLoRaMacNetworkJoined == false) {
Shaun Nelson 49:8b9e6442a02a 1841 Channel = GetNextJoinChannel(enabledChannels, nbEnabledChannels);
Shaun Nelson 49:8b9e6442a02a 1842 }
Shaun Nelson 49:8b9e6442a02a 1843 // Send first uplink on channel from same sub-band as the join
Shaun Nelson 49:8b9e6442a02a 1844 else if ((UpLinkCounter == 1) && (LastJoinBlock != -1)) {
Shaun Nelson 49:8b9e6442a02a 1845 uint8_t i;
Shaun Nelson 49:8b9e6442a02a 1846 uint8_t blockFirstChannel = LastJoinBlock * 8;
Shaun Nelson 49:8b9e6442a02a 1847
Shaun Nelson 49:8b9e6442a02a 1848 Channel = randr(blockFirstChannel, blockFirstChannel + 7);
Shaun Nelson 49:8b9e6442a02a 1849
Shaun Nelson 49:8b9e6442a02a 1850 // Check channel is enabled
Shaun Nelson 49:8b9e6442a02a 1851 for (i = 0; i < nbEnabledChannels; i++) {
Shaun Nelson 49:8b9e6442a02a 1852 if (Channel == enabledChannels[i])
Shaun Nelson 49:8b9e6442a02a 1853 break;
Shaun Nelson 49:8b9e6442a02a 1854 }
Shaun Nelson 49:8b9e6442a02a 1855
Shaun Nelson 49:8b9e6442a02a 1856 // If channel is not enabled fallback to selecting from the list of
Shaun Nelson 49:8b9e6442a02a 1857 // enabled channels
Shaun Nelson 49:8b9e6442a02a 1858 if (i == nbEnabledChannels) {
Shaun Nelson 49:8b9e6442a02a 1859 Channel = enabledChannels[randr(0, nbEnabledChannels - 1)];
Shaun Nelson 49:8b9e6442a02a 1860 }
mluis 2:14a5d6ad92d5 1861 }
mluis 2:14a5d6ad92d5 1862 else
mluis 2:14a5d6ad92d5 1863 #endif
mluis 4:37c12dbc8dc7 1864 {
Shaun Nelson 49:8b9e6442a02a 1865 Channel = enabledChannels[randr(0, nbEnabledChannels - 1)];
mluis 2:14a5d6ad92d5 1866 }
Shaun Nelson 49:8b9e6442a02a 1867
Shaun Nelson 49:8b9e6442a02a 1868 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 1869 if (Channel < (LORA_MAX_NB_CHANNELS - 8)) {
Shaun Nelson 49:8b9e6442a02a 1870 DisableChannelInMask(Channel, ChannelsMaskRemaining);
mluis 2:14a5d6ad92d5 1871 }
mluis 2:14a5d6ad92d5 1872 #endif
Shaun Nelson 49:8b9e6442a02a 1873 *time = 0;
Shaun Nelson 49:8b9e6442a02a 1874 return true;
Shaun Nelson 49:8b9e6442a02a 1875 }
Shaun Nelson 49:8b9e6442a02a 1876 else {
Shaun Nelson 49:8b9e6442a02a 1877 if (delayTx > 0) {
Shaun Nelson 49:8b9e6442a02a 1878 // Delay transmission due to AggregatedTimeOff or to a band time off
Shaun Nelson 49:8b9e6442a02a 1879 *time = nextTxDelay;
Shaun Nelson 49:8b9e6442a02a 1880 return true;
mluis 2:14a5d6ad92d5 1881 }
Shaun Nelson 49:8b9e6442a02a 1882 // Datarate not supported by any channel
Shaun Nelson 49:8b9e6442a02a 1883 *time = 0;
Shaun Nelson 49:8b9e6442a02a 1884 return false;
Shaun Nelson 49:8b9e6442a02a 1885 }
Shaun Nelson 49:8b9e6442a02a 1886 }
Shaun Nelson 49:8b9e6442a02a 1887
Shaun Nelson 49:8b9e6442a02a 1888 static void SetPublicNetwork(bool enable) {
Shaun Nelson 49:8b9e6442a02a 1889 PublicNetwork = enable;
Shaun Nelson 49:8b9e6442a02a 1890 Radio.SetModem(MODEM_LORA);
Shaun Nelson 49:8b9e6442a02a 1891 if (PublicNetwork == true) {
Shaun Nelson 49:8b9e6442a02a 1892 // Change LoRa modem SyncWord
Shaun Nelson 49:8b9e6442a02a 1893 Radio.Write(REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD);
Shaun Nelson 49:8b9e6442a02a 1894 }
Shaun Nelson 49:8b9e6442a02a 1895 else {
Shaun Nelson 49:8b9e6442a02a 1896 // Change LoRa modem SyncWord
Shaun Nelson 49:8b9e6442a02a 1897 Radio.Write(REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD);
Shaun Nelson 49:8b9e6442a02a 1898 }
Shaun Nelson 49:8b9e6442a02a 1899 }
Shaun Nelson 49:8b9e6442a02a 1900
Shaun Nelson 49:8b9e6442a02a 1901 static void RxWindowSetup(uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout,
Shaun Nelson 49:8b9e6442a02a 1902 bool rxContinuous) {
Shaun Nelson 49:8b9e6442a02a 1903 uint8_t downlinkDatarate = Datarates[datarate];
Shaun Nelson 49:8b9e6442a02a 1904 RadioModems_t modem;
Shaun Nelson 49:8b9e6442a02a 1905
Shaun Nelson 49:8b9e6442a02a 1906 if (Radio.GetStatus() == RF_IDLE) {
Shaun Nelson 49:8b9e6442a02a 1907 Radio.SetChannel(freq);
Shaun Nelson 49:8b9e6442a02a 1908
Shaun Nelson 49:8b9e6442a02a 1909 // Store downlink datarate
Shaun Nelson 49:8b9e6442a02a 1910 McpsIndication.RxDatarate = (uint8_t)datarate;
Shaun Nelson 49:8b9e6442a02a 1911
Shaun Nelson 49:8b9e6442a02a 1912 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 1913 if (datarate == DR_7) {
Shaun Nelson 49:8b9e6442a02a 1914 modem = MODEM_FSK;
Shaun Nelson 49:8b9e6442a02a 1915 Radio.SetRxConfig(modem, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0,
Shaun Nelson 49:8b9e6442a02a 1916 0, false, rxContinuous);
Shaun Nelson 49:8b9e6442a02a 1917 }
Shaun Nelson 49:8b9e6442a02a 1918 else {
Shaun Nelson 49:8b9e6442a02a 1919 modem = MODEM_LORA;
Shaun Nelson 49:8b9e6442a02a 1920 Radio.SetRxConfig(modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0,
Shaun Nelson 49:8b9e6442a02a 1921 true, rxContinuous);
Shaun Nelson 49:8b9e6442a02a 1922 }
Shaun Nelson 49:8b9e6442a02a 1923 #elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 1924 modem = MODEM_LORA;
Shaun Nelson 49:8b9e6442a02a 1925 Radio.SetRxConfig(modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0,
Shaun Nelson 49:8b9e6442a02a 1926 true, rxContinuous);
snelson 8:4816c8449bf2 1927 #endif
Shaun Nelson 49:8b9e6442a02a 1928
Shaun Nelson 49:8b9e6442a02a 1929 if (RepeaterSupport == true) {
Shaun Nelson 49:8b9e6442a02a 1930 Radio.SetMaxPayloadLength(
Shaun Nelson 49:8b9e6442a02a 1931 modem, MaxPayloadOfDatarateRepeater[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD);
Shaun Nelson 49:8b9e6442a02a 1932 }
Shaun Nelson 49:8b9e6442a02a 1933 else {
Shaun Nelson 49:8b9e6442a02a 1934 Radio.SetMaxPayloadLength(modem,
Shaun Nelson 49:8b9e6442a02a 1935 MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD);
Shaun Nelson 49:8b9e6442a02a 1936 }
Shaun Nelson 49:8b9e6442a02a 1937
Shaun Nelson 49:8b9e6442a02a 1938 if (rxContinuous == false) {
Shaun Nelson 49:8b9e6442a02a 1939 Radio.Rx(MaxRxWindow);
Shaun Nelson 49:8b9e6442a02a 1940 }
Shaun Nelson 49:8b9e6442a02a 1941 else {
Shaun Nelson 49:8b9e6442a02a 1942 Radio.Rx(0); // Continuous mode
mluis 2:14a5d6ad92d5 1943 }
Shaun Nelson 49:8b9e6442a02a 1944 }
mluis 2:14a5d6ad92d5 1945 }
mluis 2:14a5d6ad92d5 1946
Shaun Nelson 49:8b9e6442a02a 1947 static bool Rx2FreqInRange(uint32_t freq) {
Shaun Nelson 49:8b9e6442a02a 1948 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 1949 if (Radio.CheckRfFrequency(freq) == true)
Shaun Nelson 49:8b9e6442a02a 1950 #elif (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
Shaun Nelson 49:8b9e6442a02a 1951 if ((Radio.CheckRfFrequency(freq) == true) && (freq >= LORAMAC_FIRST_RX2_CHANNEL) &&
Shaun Nelson 49:8b9e6442a02a 1952 (freq <= LORAMAC_LAST_RX2_CHANNEL) && (((freq - (uint32_t)LORAMAC_FIRST_RX2_CHANNEL) %
Shaun Nelson 49:8b9e6442a02a 1953 (uint32_t)LORAMAC_STEPWIDTH_RX2_CHANNEL) == 0))
Shaun Nelson 49:8b9e6442a02a 1954 #endif
Shaun Nelson 49:8b9e6442a02a 1955 {
Shaun Nelson 49:8b9e6442a02a 1956 return true;
Shaun Nelson 49:8b9e6442a02a 1957 }
Shaun Nelson 49:8b9e6442a02a 1958 return false;
mluis 2:14a5d6ad92d5 1959 }
mluis 2:14a5d6ad92d5 1960
Shaun Nelson 49:8b9e6442a02a 1961 static bool ValidatePayloadLength(uint8_t lenN, int8_t datarate, uint8_t fOptsLen) {
Shaun Nelson 49:8b9e6442a02a 1962 uint16_t maxN = 0;
Shaun Nelson 49:8b9e6442a02a 1963 uint16_t payloadSize = 0;
Shaun Nelson 49:8b9e6442a02a 1964
Shaun Nelson 49:8b9e6442a02a 1965 // Get the maximum payload length
Shaun Nelson 49:8b9e6442a02a 1966 if (RepeaterSupport == true) {
Shaun Nelson 49:8b9e6442a02a 1967 maxN = MaxPayloadOfDatarateRepeater[datarate];
Shaun Nelson 49:8b9e6442a02a 1968 }
Shaun Nelson 49:8b9e6442a02a 1969 else {
Shaun Nelson 49:8b9e6442a02a 1970 maxN = MaxPayloadOfDatarate[datarate];
Shaun Nelson 49:8b9e6442a02a 1971 }
Shaun Nelson 49:8b9e6442a02a 1972
Shaun Nelson 49:8b9e6442a02a 1973 // Calculate the resulting payload size
Shaun Nelson 49:8b9e6442a02a 1974 payloadSize = (lenN + fOptsLen);
Shaun Nelson 49:8b9e6442a02a 1975
Shaun Nelson 49:8b9e6442a02a 1976 // Validation of the application payload size
Shaun Nelson 49:8b9e6442a02a 1977 if ((payloadSize <= maxN) && (payloadSize <= LORAMAC_PHY_MAXPAYLOAD)) {
Shaun Nelson 49:8b9e6442a02a 1978 return true;
Shaun Nelson 49:8b9e6442a02a 1979 }
Shaun Nelson 49:8b9e6442a02a 1980 return false;
Shaun Nelson 49:8b9e6442a02a 1981 }
Shaun Nelson 49:8b9e6442a02a 1982
Shaun Nelson 49:8b9e6442a02a 1983 static uint8_t CountBits(uint16_t mask, uint8_t nbBits) {
Shaun Nelson 49:8b9e6442a02a 1984 uint8_t nbActiveBits = 0;
Shaun Nelson 49:8b9e6442a02a 1985
Shaun Nelson 49:8b9e6442a02a 1986 for (uint8_t j = 0; j < nbBits; j++) {
Shaun Nelson 49:8b9e6442a02a 1987 if ((mask & (1 << j)) == (1 << j)) {
Shaun Nelson 49:8b9e6442a02a 1988 nbActiveBits++;
mluis 2:14a5d6ad92d5 1989 }
Shaun Nelson 49:8b9e6442a02a 1990 }
Shaun Nelson 49:8b9e6442a02a 1991 return nbActiveBits;
shaunkrnelson 16:1e01c8728daa 1992 }
shaunkrnelson 16:1e01c8728daa 1993
Shaun Nelson 49:8b9e6442a02a 1994 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 1995 static uint8_t CountNbEnabled125kHzChannels(uint16_t* channelsMask) {
Shaun Nelson 49:8b9e6442a02a 1996 uint8_t nb125kHzChannels = 0;
Shaun Nelson 49:8b9e6442a02a 1997
Shaun Nelson 49:8b9e6442a02a 1998 for (uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++) {
Shaun Nelson 49:8b9e6442a02a 1999 nb125kHzChannels += CountBits(channelsMask[k], 16);
Shaun Nelson 49:8b9e6442a02a 2000 }
Shaun Nelson 49:8b9e6442a02a 2001
Shaun Nelson 49:8b9e6442a02a 2002 return nb125kHzChannels;
mluis 2:14a5d6ad92d5 2003 }
mluis 2:14a5d6ad92d5 2004
Shaun Nelson 49:8b9e6442a02a 2005 #if defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2006 static void ReenableChannels(uint16_t mask, uint16_t* channelMask) {
Shaun Nelson 49:8b9e6442a02a 2007 uint16_t blockMask = mask;
Shaun Nelson 49:8b9e6442a02a 2008
Shaun Nelson 49:8b9e6442a02a 2009 for (uint8_t i = 0, j = 0; i < 4; i++, j += 2) {
Shaun Nelson 49:8b9e6442a02a 2010 channelMask[i] = 0;
Shaun Nelson 49:8b9e6442a02a 2011 if ((blockMask & (1 << j)) != 0) {
Shaun Nelson 49:8b9e6442a02a 2012 channelMask[i] |= 0x00FF;
mluis 4:37c12dbc8dc7 2013 }
Shaun Nelson 49:8b9e6442a02a 2014 if ((blockMask & (1 << (j + 1))) != 0) {
Shaun Nelson 49:8b9e6442a02a 2015 channelMask[i] |= 0xFF00;
mluis 4:37c12dbc8dc7 2016 }
Shaun Nelson 49:8b9e6442a02a 2017 }
Shaun Nelson 49:8b9e6442a02a 2018 channelMask[4] = blockMask;
Shaun Nelson 49:8b9e6442a02a 2019 channelMask[5] = 0x0000;
mluis 4:37c12dbc8dc7 2020 }
mluis 4:37c12dbc8dc7 2021
Shaun Nelson 49:8b9e6442a02a 2022 static bool ValidateChannelMask(uint16_t* channelMask) {
Shaun Nelson 49:8b9e6442a02a 2023 bool chanMaskState = false;
Shaun Nelson 49:8b9e6442a02a 2024 uint16_t block1 = 0;
Shaun Nelson 49:8b9e6442a02a 2025 uint16_t block2 = 0;
Shaun Nelson 49:8b9e6442a02a 2026 uint8_t index = 0;
Shaun Nelson 49:8b9e6442a02a 2027
Shaun Nelson 49:8b9e6442a02a 2028 for (uint8_t i = 0; i < 4; i++) {
Shaun Nelson 49:8b9e6442a02a 2029 block1 = channelMask[i] & 0x00FF;
Shaun Nelson 49:8b9e6442a02a 2030 block2 = channelMask[i] & 0xFF00;
Shaun Nelson 49:8b9e6442a02a 2031
Shaun Nelson 49:8b9e6442a02a 2032 if ((CountBits(block1, 16) > 5) && (chanMaskState == false)) {
Shaun Nelson 49:8b9e6442a02a 2033 channelMask[i] &= block1;
Shaun Nelson 49:8b9e6442a02a 2034 channelMask[4] = 1 << (i * 2);
Shaun Nelson 49:8b9e6442a02a 2035 chanMaskState = true;
Shaun Nelson 49:8b9e6442a02a 2036 index = i;
mluis 4:37c12dbc8dc7 2037 }
Shaun Nelson 49:8b9e6442a02a 2038 else if ((CountBits(block2, 16) > 5) && (chanMaskState == false)) {
Shaun Nelson 49:8b9e6442a02a 2039 channelMask[i] &= block2;
Shaun Nelson 49:8b9e6442a02a 2040 channelMask[4] = 1 << (i * 2 + 1);
Shaun Nelson 49:8b9e6442a02a 2041 chanMaskState = true;
Shaun Nelson 49:8b9e6442a02a 2042 index = i;
mluis 4:37c12dbc8dc7 2043 }
Shaun Nelson 49:8b9e6442a02a 2044 }
Shaun Nelson 49:8b9e6442a02a 2045
Shaun Nelson 49:8b9e6442a02a 2046 // Do only change the channel mask, if we have found a valid block.
Shaun Nelson 49:8b9e6442a02a 2047 if (chanMaskState == true) {
Shaun Nelson 49:8b9e6442a02a 2048 for (uint8_t i = 0; i < 4; i++) {
Shaun Nelson 49:8b9e6442a02a 2049 if (i != index) {
Shaun Nelson 49:8b9e6442a02a 2050 channelMask[i] = 0;
Shaun Nelson 49:8b9e6442a02a 2051 }
Shaun Nelson 49:8b9e6442a02a 2052 }
Shaun Nelson 49:8b9e6442a02a 2053 }
Shaun Nelson 49:8b9e6442a02a 2054 return chanMaskState;
mluis 4:37c12dbc8dc7 2055 }
mluis 4:37c12dbc8dc7 2056 #endif
mluis 2:14a5d6ad92d5 2057 #endif
mluis 2:14a5d6ad92d5 2058
Shaun Nelson 49:8b9e6442a02a 2059 static int8_t LimitTxPower(int8_t txPower) {
Shaun Nelson 49:8b9e6442a02a 2060 int8_t resultTxPower = MAX(txPower, TX_POWER_30_DBM);
Shaun Nelson 49:8b9e6442a02a 2061
Shaun Nelson 49:8b9e6442a02a 2062 return resultTxPower;
mluis 2:14a5d6ad92d5 2063 }
mluis 2:14a5d6ad92d5 2064
Shaun Nelson 49:8b9e6442a02a 2065 static bool ValueInRange(int8_t value, int8_t min, int8_t max) {
Shaun Nelson 49:8b9e6442a02a 2066 if ((value >= min) && (value <= max)) {
Shaun Nelson 49:8b9e6442a02a 2067 return true;
Shaun Nelson 49:8b9e6442a02a 2068 }
Shaun Nelson 49:8b9e6442a02a 2069 return false;
mluis 2:14a5d6ad92d5 2070 }
mluis 2:14a5d6ad92d5 2071
Shaun Nelson 49:8b9e6442a02a 2072 static bool DisableChannelInMask(uint8_t id, uint16_t* mask) {
Shaun Nelson 49:8b9e6442a02a 2073 uint8_t index = 0;
Shaun Nelson 49:8b9e6442a02a 2074 index = id / 16;
Shaun Nelson 49:8b9e6442a02a 2075
Shaun Nelson 49:8b9e6442a02a 2076 if ((index > 4) || (id >= LORA_MAX_NB_CHANNELS)) {
Shaun Nelson 49:8b9e6442a02a 2077 return false;
Shaun Nelson 49:8b9e6442a02a 2078 }
Shaun Nelson 49:8b9e6442a02a 2079
Shaun Nelson 49:8b9e6442a02a 2080 // Deactivate channel
Shaun Nelson 49:8b9e6442a02a 2081 mask[index] &= ~(1 << (id % 16));
Shaun Nelson 49:8b9e6442a02a 2082
Shaun Nelson 49:8b9e6442a02a 2083 return true;
mluis 2:14a5d6ad92d5 2084 }
mluis 2:14a5d6ad92d5 2085
Shaun Nelson 49:8b9e6442a02a 2086 static bool AdrNextDr(bool adrEnabled, bool isTx, int8_t* datarateOut, int8_t* txpowerOut) {
Shaun Nelson 49:8b9e6442a02a 2087 bool adrAckReq = false;
Shaun Nelson 49:8b9e6442a02a 2088 int8_t datarate = ChannelsDatarate;
Shaun Nelson 49:8b9e6442a02a 2089 int8_t txpower = ChannelsTxPower;
Shaun Nelson 49:8b9e6442a02a 2090
Shaun Nelson 49:8b9e6442a02a 2091 if (adrEnabled == true) {
Shaun Nelson 49:8b9e6442a02a 2092 /* Request ADR Ack Request (including at lowest available datarate) */
Shaun Nelson 49:8b9e6442a02a 2093 adrAckReq = AdrAckCounter >= ADR_ACK_LIMIT ? true : false;
Shaun Nelson 49:8b9e6442a02a 2094
Shaun Nelson 49:8b9e6442a02a 2095 if (AdrAckCounter >= (ADR_ACK_LIMIT + ADR_ACK_DELAY)) {
Shaun Nelson 49:8b9e6442a02a 2096 // Step up power
Shaun Nelson 49:8b9e6442a02a 2097 txpower = LORAMAC_DEFAULT_TX_POWER;
Shaun Nelson 49:8b9e6442a02a 2098
Shaun Nelson 49:8b9e6442a02a 2099 if ((AdrAckCounter % ADR_ACK_DELAY) == 0) {
Shaun Nelson 49:8b9e6442a02a 2100 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 2101 if (datarate > LORAMAC_TX_MIN_DATARATE) {
Shaun Nelson 49:8b9e6442a02a 2102 datarate--;
Shaun Nelson 49:8b9e6442a02a 2103 }
Shaun Nelson 49:8b9e6442a02a 2104
Shaun Nelson 49:8b9e6442a02a 2105 if (datarate == LORAMAC_TX_MIN_DATARATE) {
Shaun Nelson 49:8b9e6442a02a 2106 if (isTx == true) {
Shaun Nelson 49:8b9e6442a02a 2107 // Re-enable default channels LC1, LC2, LC3
Shaun Nelson 49:8b9e6442a02a 2108 ChannelsMask[0] = ChannelsMask[0] | (LC(1) + LC(2) + LC(3));
Shaun Nelson 49:8b9e6442a02a 2109 }
Shaun Nelson 49:8b9e6442a02a 2110 }
Shaun Nelson 49:8b9e6442a02a 2111 #elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2112 if (datarate > LORAMAC_TX_MIN_DATARATE) {
Shaun Nelson 49:8b9e6442a02a 2113 if (datarate == DR_8)
Shaun Nelson 49:8b9e6442a02a 2114 datarate = DR_4;
Shaun Nelson 49:8b9e6442a02a 2115 else
Shaun Nelson 49:8b9e6442a02a 2116 datarate--;
Shaun Nelson 49:8b9e6442a02a 2117 }
Shaun Nelson 49:8b9e6442a02a 2118 else if (isTx == true) {
Shaun Nelson 49:8b9e6442a02a 2119 #if defined(USE_BAND_915)
Shaun Nelson 49:8b9e6442a02a 2120 // Re-enable default channels
Shaun Nelson 49:8b9e6442a02a 2121 ChannelsMask[0] = 0xFFFF;
Shaun Nelson 49:8b9e6442a02a 2122 ChannelsMask[1] = 0xFFFF;
Shaun Nelson 49:8b9e6442a02a 2123 ChannelsMask[2] = 0xFFFF;
Shaun Nelson 49:8b9e6442a02a 2124 ChannelsMask[3] = 0xFFFF;
Shaun Nelson 49:8b9e6442a02a 2125 ChannelsMask[4] = 0x00FF;
Shaun Nelson 49:8b9e6442a02a 2126 ChannelsMask[5] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2127 #else // defined( USE_BAND_915_HYBRID )
Shaun Nelson 49:8b9e6442a02a 2128 // Re-enable default channels
Shaun Nelson 49:8b9e6442a02a 2129 ChannelsMask[0] = 0x00FF;
Shaun Nelson 49:8b9e6442a02a 2130 ChannelsMask[1] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2131 ChannelsMask[2] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2132 ChannelsMask[3] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2133 ChannelsMask[4] = 0x0001;
Shaun Nelson 49:8b9e6442a02a 2134 ChannelsMask[5] = 0x0000;
mluis 3:b9d87593a8ae 2135 #endif
Shaun Nelson 49:8b9e6442a02a 2136 }
mluis 2:14a5d6ad92d5 2137 #else
mluis 2:14a5d6ad92d5 2138 #error "Please define a frequency band in the compiler options."
mluis 2:14a5d6ad92d5 2139 #endif
Shaun Nelson 49:8b9e6442a02a 2140 }
mluis 0:91d1a7783bb9 2141 }
Shaun Nelson 49:8b9e6442a02a 2142 }
Shaun Nelson 49:8b9e6442a02a 2143
Shaun Nelson 49:8b9e6442a02a 2144 if (datarateOut != NULL)
Shaun Nelson 49:8b9e6442a02a 2145 *datarateOut = datarate;
Shaun Nelson 49:8b9e6442a02a 2146
Shaun Nelson 49:8b9e6442a02a 2147 if (txpowerOut != NULL)
Shaun Nelson 49:8b9e6442a02a 2148 *txpowerOut = txpower;
Shaun Nelson 49:8b9e6442a02a 2149
Shaun Nelson 49:8b9e6442a02a 2150 return adrAckReq;
mluis 0:91d1a7783bb9 2151 }
mluis 0:91d1a7783bb9 2152
Shaun Nelson 49:8b9e6442a02a 2153 static LoRaMacStatus_t AddMacCommand(uint8_t cmd, uint8_t p1, uint8_t p2) {
Shaun Nelson 49:8b9e6442a02a 2154 LoRaMacStatus_t status = LORAMAC_STATUS_BUSY;
Shaun Nelson 49:8b9e6442a02a 2155 // The maximum buffer length must take MAC commands to re-send into account.
Shaun Nelson 49:8b9e6442a02a 2156 uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex;
Shaun Nelson 49:8b9e6442a02a 2157
Shaun Nelson 49:8b9e6442a02a 2158 switch (cmd) {
Shaun Nelson 49:8b9e6442a02a 2159 case MOTE_MAC_LINK_CHECK_REQ:
Shaun Nelson 49:8b9e6442a02a 2160 if (MacCommandsBufferIndex < bufLen) {
Shaun Nelson 49:8b9e6442a02a 2161 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Shaun Nelson 49:8b9e6442a02a 2162 // No payload for this command
Shaun Nelson 49:8b9e6442a02a 2163 status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2164 }
Shaun Nelson 49:8b9e6442a02a 2165 break;
Shaun Nelson 49:8b9e6442a02a 2166 case MOTE_MAC_LINK_ADR_ANS:
Shaun Nelson 49:8b9e6442a02a 2167 if (MacCommandsBufferIndex < (bufLen - 1)) {
Shaun Nelson 49:8b9e6442a02a 2168 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Shaun Nelson 49:8b9e6442a02a 2169 // Margin
Shaun Nelson 49:8b9e6442a02a 2170 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Shaun Nelson 49:8b9e6442a02a 2171 status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2172 }
Shaun Nelson 49:8b9e6442a02a 2173 break;
Shaun Nelson 49:8b9e6442a02a 2174 case MOTE_MAC_DUTY_CYCLE_ANS:
Shaun Nelson 49:8b9e6442a02a 2175 if (MacCommandsBufferIndex < bufLen) {
Shaun Nelson 49:8b9e6442a02a 2176 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Shaun Nelson 49:8b9e6442a02a 2177 // No payload for this answer
Shaun Nelson 49:8b9e6442a02a 2178 status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2179 }
Shaun Nelson 49:8b9e6442a02a 2180 break;
Shaun Nelson 49:8b9e6442a02a 2181 case MOTE_MAC_RX_PARAM_SETUP_ANS:
Shaun Nelson 49:8b9e6442a02a 2182 if (MacCommandsBufferIndex < (bufLen - 1)) {
Shaun Nelson 49:8b9e6442a02a 2183 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Shaun Nelson 49:8b9e6442a02a 2184 // Status: Datarate ACK, Channel ACK
Shaun Nelson 49:8b9e6442a02a 2185 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Shaun Nelson 49:8b9e6442a02a 2186 status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2187 }
Shaun Nelson 49:8b9e6442a02a 2188 break;
Shaun Nelson 49:8b9e6442a02a 2189 case MOTE_MAC_DEV_STATUS_ANS:
Shaun Nelson 49:8b9e6442a02a 2190 if (MacCommandsBufferIndex < (bufLen - 2)) {
Shaun Nelson 49:8b9e6442a02a 2191 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Shaun Nelson 49:8b9e6442a02a 2192 // 1st byte Battery
Shaun Nelson 49:8b9e6442a02a 2193 // 2nd byte Margin
Shaun Nelson 49:8b9e6442a02a 2194 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Shaun Nelson 49:8b9e6442a02a 2195 MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
Shaun Nelson 49:8b9e6442a02a 2196 status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2197 }
Shaun Nelson 49:8b9e6442a02a 2198 break;
Shaun Nelson 49:8b9e6442a02a 2199 case MOTE_MAC_NEW_CHANNEL_ANS:
Shaun Nelson 49:8b9e6442a02a 2200 if (MacCommandsBufferIndex < (bufLen - 1)) {
Shaun Nelson 49:8b9e6442a02a 2201 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Shaun Nelson 49:8b9e6442a02a 2202 // Status: Datarate range OK, Channel frequency OK
Shaun Nelson 49:8b9e6442a02a 2203 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Shaun Nelson 49:8b9e6442a02a 2204 status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2205 }
Shaun Nelson 49:8b9e6442a02a 2206 break;
Shaun Nelson 49:8b9e6442a02a 2207 case MOTE_MAC_RX_TIMING_SETUP_ANS:
Shaun Nelson 49:8b9e6442a02a 2208 if (MacCommandsBufferIndex < bufLen) {
Shaun Nelson 49:8b9e6442a02a 2209 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Shaun Nelson 49:8b9e6442a02a 2210 // No payload for this answer
Shaun Nelson 49:8b9e6442a02a 2211 status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2212 }
Shaun Nelson 49:8b9e6442a02a 2213 break;
Shaun Nelson 49:8b9e6442a02a 2214 default:
Shaun Nelson 49:8b9e6442a02a 2215 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Shaun Nelson 49:8b9e6442a02a 2216 }
Shaun Nelson 49:8b9e6442a02a 2217 if (status == LORAMAC_STATUS_OK) {
Shaun Nelson 49:8b9e6442a02a 2218 MacCommandsInNextTx = true;
Shaun Nelson 49:8b9e6442a02a 2219 }
Shaun Nelson 49:8b9e6442a02a 2220 return status;
Shaun Nelson 49:8b9e6442a02a 2221 }
Shaun Nelson 49:8b9e6442a02a 2222
Shaun Nelson 49:8b9e6442a02a 2223 static uint8_t ParseMacCommandsToRepeat(uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut) {
Shaun Nelson 49:8b9e6442a02a 2224 uint8_t i = 0;
Shaun Nelson 49:8b9e6442a02a 2225 uint8_t cmdCount = 0;
Shaun Nelson 49:8b9e6442a02a 2226
Shaun Nelson 49:8b9e6442a02a 2227 if ((cmdBufIn == NULL) || (cmdBufOut == NULL)) {
Shaun Nelson 49:8b9e6442a02a 2228 return 0;
Shaun Nelson 49:8b9e6442a02a 2229 }
Shaun Nelson 49:8b9e6442a02a 2230
Shaun Nelson 49:8b9e6442a02a 2231 for (i = 0; i < length; i++) {
Shaun Nelson 49:8b9e6442a02a 2232 switch (cmdBufIn[i]) {
Shaun Nelson 49:8b9e6442a02a 2233 case MOTE_MAC_RX_PARAM_SETUP_ANS: {
Shaun Nelson 49:8b9e6442a02a 2234 cmdBufOut[cmdCount++] = cmdBufIn[i++];
Shaun Nelson 49:8b9e6442a02a 2235 cmdBufOut[cmdCount++] = cmdBufIn[i++];
Shaun Nelson 49:8b9e6442a02a 2236 cmdBufOut[cmdCount++] = cmdBufIn[i];
Shaun Nelson 49:8b9e6442a02a 2237 break;
Shaun Nelson 49:8b9e6442a02a 2238 }
Shaun Nelson 49:8b9e6442a02a 2239 case MOTE_MAC_RX_TIMING_SETUP_ANS: {
Shaun Nelson 49:8b9e6442a02a 2240 cmdBufOut[cmdCount++] = cmdBufIn[i];
Shaun Nelson 49:8b9e6442a02a 2241 break;
Shaun Nelson 49:8b9e6442a02a 2242 }
Shaun Nelson 49:8b9e6442a02a 2243 default:
Shaun Nelson 49:8b9e6442a02a 2244 break;
mluis 0:91d1a7783bb9 2245 }
Shaun Nelson 49:8b9e6442a02a 2246 }
Shaun Nelson 49:8b9e6442a02a 2247
Shaun Nelson 49:8b9e6442a02a 2248 return cmdCount;
Shaun Nelson 27:cda377b2a41f 2249 }
Shaun Nelson 27:cda377b2a41f 2250
Shaun Nelson 49:8b9e6442a02a 2251 static void ProcessMacCommands(uint8_t* payload, uint8_t macIndex, uint8_t commandsSize,
Shaun Nelson 49:8b9e6442a02a 2252 uint8_t snr) {
Shaun Nelson 49:8b9e6442a02a 2253 uint8_t validLinkAdrCmds = 0;
Shaun Nelson 49:8b9e6442a02a 2254 int8_t txPower = 0;
Shaun Nelson 49:8b9e6442a02a 2255 int8_t datarate = 0;
Shaun Nelson 49:8b9e6442a02a 2256 uint8_t nbRep = 0;
Shaun Nelson 49:8b9e6442a02a 2257 uint16_t channelsMask[6] = {0, 0, 0, 0, 0, 0};
Shaun Nelson 49:8b9e6442a02a 2258 uint8_t LinkAdrMacCmdBufferIndex = 0;
Shaun Nelson 49:8b9e6442a02a 2259
Shaun Nelson 49:8b9e6442a02a 2260 while (macIndex < commandsSize) {
Shaun Nelson 49:8b9e6442a02a 2261 // Decode Frame MAC commands
Shaun Nelson 49:8b9e6442a02a 2262 switch (payload[macIndex++]) {
Shaun Nelson 49:8b9e6442a02a 2263 case SRV_MAC_LINK_CHECK_ANS:
Shaun Nelson 49:8b9e6442a02a 2264 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2265 MlmeConfirm.DemodMargin = payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2266 MlmeConfirm.NbGateways = payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2267 break;
Shaun Nelson 49:8b9e6442a02a 2268 case SRV_MAC_LINK_ADR_REQ: {
Shaun Nelson 49:8b9e6442a02a 2269 uint8_t chMaskCntl = 0;
Shaun Nelson 49:8b9e6442a02a 2270 uint8_t status = 0x07;
Shaun Nelson 49:8b9e6442a02a 2271 uint16_t chMask;
Shaun Nelson 49:8b9e6442a02a 2272
Shaun Nelson 49:8b9e6442a02a 2273 datarate = payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2274 txPower = datarate & 0x0F;
Shaun Nelson 49:8b9e6442a02a 2275 datarate = (datarate >> 4) & 0x0F;
Shaun Nelson 49:8b9e6442a02a 2276
Shaun Nelson 49:8b9e6442a02a 2277 if ((AdrCtrlOn == false) &&
Shaun Nelson 49:8b9e6442a02a 2278 ((ChannelsDatarate != datarate) ||
Shaun Nelson 49:8b9e6442a02a 2279 (ChannelsTxPower != txPower))) { // ADR disabled don't handle ADR
Shaun Nelson 49:8b9e6442a02a 2280 // requests if server tries to
Shaun Nelson 49:8b9e6442a02a 2281 // change datarate or txpower
Shaun Nelson 49:8b9e6442a02a 2282 // Answer the server with fail status
Shaun Nelson 49:8b9e6442a02a 2283 // Power ACK = 0
Shaun Nelson 49:8b9e6442a02a 2284 // Data rate ACK = 0
Shaun Nelson 49:8b9e6442a02a 2285 // Channel mask = 0
Shaun Nelson 49:8b9e6442a02a 2286 AddMacCommand(MOTE_MAC_LINK_ADR_ANS, 0, 0);
Shaun Nelson 49:8b9e6442a02a 2287 macIndex += 3; // Skip over the remaining bytes of the request
Shaun Nelson 49:8b9e6442a02a 2288 break;
Shaun Nelson 49:8b9e6442a02a 2289 }
Shaun Nelson 49:8b9e6442a02a 2290 else if (validLinkAdrCmds++ == 0) {
Shaun Nelson 49:8b9e6442a02a 2291 // Initialize local copy of the channels mask array
Shaun Nelson 49:8b9e6442a02a 2292 for (uint8_t i = 0; i < 6; i++) {
Shaun Nelson 49:8b9e6442a02a 2293 channelsMask[i] = ChannelsMask[i];
Shaun Nelson 49:8b9e6442a02a 2294 }
Shaun Nelson 49:8b9e6442a02a 2295 }
Shaun Nelson 49:8b9e6442a02a 2296
Shaun Nelson 49:8b9e6442a02a 2297 chMask = (uint16_t)payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2298 chMask |= (uint16_t)payload[macIndex++] << 8;
Shaun Nelson 49:8b9e6442a02a 2299
Shaun Nelson 49:8b9e6442a02a 2300 nbRep = payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2301 chMaskCntl = (nbRep >> 4) & 0x07;
Shaun Nelson 49:8b9e6442a02a 2302 nbRep &= 0x0F;
Shaun Nelson 49:8b9e6442a02a 2303 if (nbRep == 0) {
Shaun Nelson 49:8b9e6442a02a 2304 nbRep = 1;
Shaun Nelson 49:8b9e6442a02a 2305 }
Shaun Nelson 49:8b9e6442a02a 2306 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 2307 if ((chMaskCntl == 0) && (chMask == 0)) {
Shaun Nelson 49:8b9e6442a02a 2308 status &= 0xFE; // Channel mask KO
Shaun Nelson 49:8b9e6442a02a 2309 }
Shaun Nelson 49:8b9e6442a02a 2310 else if (((chMaskCntl >= 1) && (chMaskCntl <= 5)) || (chMaskCntl >= 7)) {
Shaun Nelson 49:8b9e6442a02a 2311 // RFU
Shaun Nelson 49:8b9e6442a02a 2312 status &= 0xFE; // Channel mask KO
Shaun Nelson 49:8b9e6442a02a 2313 }
Shaun Nelson 49:8b9e6442a02a 2314 else {
Shaun Nelson 49:8b9e6442a02a 2315 for (i = 0; i < LORA_MAX_NB_CHANNELS; i++) {
Shaun Nelson 49:8b9e6442a02a 2316 if (chMaskCntl == 6) {
Shaun Nelson 49:8b9e6442a02a 2317 if (Channels[i].Frequency != 0) {
Shaun Nelson 49:8b9e6442a02a 2318 chMask |= 1 << i;
Shaun Nelson 49:8b9e6442a02a 2319 }
Shaun Nelson 49:8b9e6442a02a 2320 }
Shaun Nelson 49:8b9e6442a02a 2321 else {
Shaun Nelson 49:8b9e6442a02a 2322 if (((chMask & (1 << i)) != 0) &&
Shaun Nelson 49:8b9e6442a02a 2323 (Channels[i].Frequency == 0)) { // Trying to enable an undefined channel
Shaun Nelson 49:8b9e6442a02a 2324 status &= 0xFE; // Channel mask KO
Shaun Nelson 49:8b9e6442a02a 2325 }
Shaun Nelson 49:8b9e6442a02a 2326 }
Shaun Nelson 49:8b9e6442a02a 2327 }
Shaun Nelson 49:8b9e6442a02a 2328 channelsMask[0] = chMask;
Shaun Nelson 49:8b9e6442a02a 2329 }
Shaun Nelson 49:8b9e6442a02a 2330 #elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2331 if (chMaskCntl < 4) {
Shaun Nelson 49:8b9e6442a02a 2332 channelsMask[chMaskCntl] = chMask;
Shaun Nelson 49:8b9e6442a02a 2333 }
Shaun Nelson 49:8b9e6442a02a 2334 else if (chMaskCntl == 6) {
Shaun Nelson 49:8b9e6442a02a 2335 // Enable all 125 kHz channels
Shaun Nelson 49:8b9e6442a02a 2336 for (uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++) {
Shaun Nelson 49:8b9e6442a02a 2337 for (uint8_t j = 0; j < 16; j++) {
Shaun Nelson 49:8b9e6442a02a 2338 if (Channels[i + j].Frequency != 0) {
Shaun Nelson 49:8b9e6442a02a 2339 channelsMask[k] |= 1 << j;
Shaun Nelson 49:8b9e6442a02a 2340 }
Shaun Nelson 49:8b9e6442a02a 2341 }
Shaun Nelson 49:8b9e6442a02a 2342 }
Shaun Nelson 49:8b9e6442a02a 2343 // channel mask applied to 500 kHz channels
Shaun Nelson 49:8b9e6442a02a 2344 channelsMask[4] = chMask;
Shaun Nelson 49:8b9e6442a02a 2345 }
Shaun Nelson 49:8b9e6442a02a 2346 else if (chMaskCntl == 7) {
Shaun Nelson 49:8b9e6442a02a 2347 // Disable all 125 kHz channels
Shaun Nelson 49:8b9e6442a02a 2348 channelsMask[0] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2349 channelsMask[1] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2350 channelsMask[2] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2351 channelsMask[3] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2352
Shaun Nelson 49:8b9e6442a02a 2353 // channel mask applied to 500 kHz channels
Shaun Nelson 49:8b9e6442a02a 2354 channelsMask[4] = chMask;
Shaun Nelson 49:8b9e6442a02a 2355 }
Shaun Nelson 49:8b9e6442a02a 2356 else {
Shaun Nelson 49:8b9e6442a02a 2357 // RFU
Shaun Nelson 49:8b9e6442a02a 2358 status &= 0xFE; // Channel mask KO
Shaun Nelson 49:8b9e6442a02a 2359 }
mluis 0:91d1a7783bb9 2360 #else
Shaun Nelson 49:8b9e6442a02a 2361 #error "Please define a frequency band in the compiler options."
mluis 0:91d1a7783bb9 2362 #endif
Shaun Nelson 49:8b9e6442a02a 2363 if (ValueInRange(datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE) == false) {
Shaun Nelson 49:8b9e6442a02a 2364 status &= 0xFD; // Datarate KO
Shaun Nelson 49:8b9e6442a02a 2365 }
Shaun Nelson 49:8b9e6442a02a 2366
Shaun Nelson 49:8b9e6442a02a 2367 //
Shaun Nelson 49:8b9e6442a02a 2368 // Remark MaxTxPower = 0 and MinTxPower = 5
Shaun Nelson 49:8b9e6442a02a 2369 //
Shaun Nelson 49:8b9e6442a02a 2370 if (ValueInRange(txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER) == false) {
Shaun Nelson 49:8b9e6442a02a 2371 status &= 0xFB; // TxPower KO
Shaun Nelson 49:8b9e6442a02a 2372 }
Shaun Nelson 49:8b9e6442a02a 2373
Shaun Nelson 49:8b9e6442a02a 2374 // Save the mac command status location for possible channel mask KO
Shaun Nelson 49:8b9e6442a02a 2375 // later
Shaun Nelson 49:8b9e6442a02a 2376 LinkAdrMacCmdBufferIndex = MacCommandsBufferIndex;
Shaun Nelson 49:8b9e6442a02a 2377
Shaun Nelson 49:8b9e6442a02a 2378 AddMacCommand(MOTE_MAC_LINK_ADR_ANS, status, 0);
Shaun Nelson 49:8b9e6442a02a 2379 } break;
Shaun Nelson 49:8b9e6442a02a 2380 case SRV_MAC_DUTY_CYCLE_REQ:
Shaun Nelson 49:8b9e6442a02a 2381 MaxDCycle = payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2382 AggregatedDCycle = 1 << MaxDCycle;
Shaun Nelson 49:8b9e6442a02a 2383 AddMacCommand(MOTE_MAC_DUTY_CYCLE_ANS, 0, 0);
Shaun Nelson 49:8b9e6442a02a 2384 break;
Shaun Nelson 49:8b9e6442a02a 2385 case SRV_MAC_RX_PARAM_SETUP_REQ: {
Shaun Nelson 49:8b9e6442a02a 2386 uint8_t status = 0x07;
Shaun Nelson 49:8b9e6442a02a 2387 int8_t datarate = 0;
Shaun Nelson 49:8b9e6442a02a 2388 int8_t drOffset = 0;
Shaun Nelson 49:8b9e6442a02a 2389 uint32_t freq = 0;
Shaun Nelson 49:8b9e6442a02a 2390
Shaun Nelson 49:8b9e6442a02a 2391 drOffset = (payload[macIndex] >> 4) & 0x07;
Shaun Nelson 49:8b9e6442a02a 2392 datarate = payload[macIndex] & 0x0F;
Shaun Nelson 49:8b9e6442a02a 2393 macIndex++;
Shaun Nelson 49:8b9e6442a02a 2394
Shaun Nelson 49:8b9e6442a02a 2395 freq = (uint32_t)payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2396 freq |= (uint32_t)payload[macIndex++] << 8;
Shaun Nelson 49:8b9e6442a02a 2397 freq |= (uint32_t)payload[macIndex++] << 16;
Shaun Nelson 49:8b9e6442a02a 2398 freq *= 100;
Shaun Nelson 49:8b9e6442a02a 2399
Shaun Nelson 49:8b9e6442a02a 2400 if (Rx2FreqInRange(freq) == false) {
Shaun Nelson 49:8b9e6442a02a 2401 status &= 0xFE; // Channel frequency KO
Shaun Nelson 49:8b9e6442a02a 2402 }
Shaun Nelson 49:8b9e6442a02a 2403
Shaun Nelson 49:8b9e6442a02a 2404 if (ValueInRange(datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE) == false) {
Shaun Nelson 49:8b9e6442a02a 2405 status &= 0xFD; // Datarate KO
Shaun Nelson 49:8b9e6442a02a 2406 }
Shaun Nelson 49:8b9e6442a02a 2407 #if (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
Shaun Nelson 49:8b9e6442a02a 2408 if ((ValueInRange(datarate, DR_5, DR_7) == true) || (datarate > DR_13)) {
Shaun Nelson 49:8b9e6442a02a 2409 status &= 0xFD; // Datarate KO
Shaun Nelson 49:8b9e6442a02a 2410 }
mluis 2:14a5d6ad92d5 2411 #endif
Shaun Nelson 49:8b9e6442a02a 2412 if (ValueInRange(drOffset, LORAMAC_MIN_RX1_DR_OFFSET, LORAMAC_MAX_RX1_DR_OFFSET) == false) {
Shaun Nelson 49:8b9e6442a02a 2413 status &= 0xFB; // Rx1DrOffset range KO
Shaun Nelson 49:8b9e6442a02a 2414 }
Shaun Nelson 49:8b9e6442a02a 2415
Shaun Nelson 49:8b9e6442a02a 2416 if ((status & 0x07) == 0x07) {
Shaun Nelson 49:8b9e6442a02a 2417 Rx2Channel.Datarate = datarate;
Shaun Nelson 49:8b9e6442a02a 2418 Rx2Channel.Frequency = freq;
Shaun Nelson 49:8b9e6442a02a 2419 Rx1DrOffset = drOffset;
Shaun Nelson 49:8b9e6442a02a 2420 }
Shaun Nelson 49:8b9e6442a02a 2421 AddMacCommand(MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0);
Shaun Nelson 49:8b9e6442a02a 2422 } break;
Shaun Nelson 49:8b9e6442a02a 2423 case SRV_MAC_DEV_STATUS_REQ: {
Shaun Nelson 49:8b9e6442a02a 2424 uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
Shaun Nelson 49:8b9e6442a02a 2425 if ((LoRaMacCallbacks != NULL) && (LoRaMacCallbacks->GetBatteryLevel != NULL)) {
Shaun Nelson 49:8b9e6442a02a 2426 batteryLevel = LoRaMacCallbacks->GetBatteryLevel();
Shaun Nelson 49:8b9e6442a02a 2427 }
Shaun Nelson 49:8b9e6442a02a 2428 AddMacCommand(MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr);
Shaun Nelson 49:8b9e6442a02a 2429 break;
Shaun Nelson 49:8b9e6442a02a 2430 }
Shaun Nelson 49:8b9e6442a02a 2431 case SRV_MAC_NEW_CHANNEL_REQ: {
Shaun Nelson 49:8b9e6442a02a 2432 uint8_t status = 0x03;
Shaun Nelson 49:8b9e6442a02a 2433
Shaun Nelson 49:8b9e6442a02a 2434 #if (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
Shaun Nelson 49:8b9e6442a02a 2435 status &= 0xFC; // Channel frequency and datarate KO
Shaun Nelson 49:8b9e6442a02a 2436 macIndex += 5;
mluis 2:14a5d6ad92d5 2437 #else
Shaun Nelson 49:8b9e6442a02a 2438 int8_t channelIndex = 0;
Shaun Nelson 49:8b9e6442a02a 2439 ChannelParams_t chParam;
Shaun Nelson 49:8b9e6442a02a 2440
Shaun Nelson 49:8b9e6442a02a 2441 channelIndex = payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2442 chParam.Frequency = (uint32_t)payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2443 chParam.Frequency |= (uint32_t)payload[macIndex++] << 8;
Shaun Nelson 49:8b9e6442a02a 2444 chParam.Frequency |= (uint32_t)payload[macIndex++] << 16;
Shaun Nelson 49:8b9e6442a02a 2445 chParam.Frequency *= 100;
Shaun Nelson 49:8b9e6442a02a 2446 chParam.DrRange.Value = payload[macIndex++];
Shaun Nelson 49:8b9e6442a02a 2447
Shaun Nelson 49:8b9e6442a02a 2448 LoRaMacState |= MAC_TX_CONFIG;
Shaun Nelson 49:8b9e6442a02a 2449 if (chParam.Frequency == 0) {
Shaun Nelson 49:8b9e6442a02a 2450 if (channelIndex < 3) {
Shaun Nelson 49:8b9e6442a02a 2451 status &= 0xFC;
Shaun Nelson 49:8b9e6442a02a 2452 }
Shaun Nelson 49:8b9e6442a02a 2453 else {
Shaun Nelson 49:8b9e6442a02a 2454 if (LoRaMacChannelRemove(channelIndex) != LORAMAC_STATUS_OK) {
Shaun Nelson 49:8b9e6442a02a 2455 status &= 0xFC;
Shaun Nelson 49:8b9e6442a02a 2456 }
Shaun Nelson 49:8b9e6442a02a 2457 }
Shaun Nelson 49:8b9e6442a02a 2458 }
Shaun Nelson 49:8b9e6442a02a 2459 else {
Shaun Nelson 49:8b9e6442a02a 2460 switch (LoRaMacChannelAdd(channelIndex, chParam)) {
Shaun Nelson 49:8b9e6442a02a 2461 case LORAMAC_STATUS_OK: {
Shaun Nelson 49:8b9e6442a02a 2462 break;
Shaun Nelson 49:8b9e6442a02a 2463 }
Shaun Nelson 49:8b9e6442a02a 2464 case LORAMAC_STATUS_FREQUENCY_INVALID: {
Shaun Nelson 49:8b9e6442a02a 2465 status &= 0xFE;
Shaun Nelson 49:8b9e6442a02a 2466 break;
Shaun Nelson 49:8b9e6442a02a 2467 }
Shaun Nelson 49:8b9e6442a02a 2468 case LORAMAC_STATUS_DATARATE_INVALID: {
Shaun Nelson 49:8b9e6442a02a 2469 status &= 0xFD;
Shaun Nelson 49:8b9e6442a02a 2470 break;
Shaun Nelson 49:8b9e6442a02a 2471 }
Shaun Nelson 49:8b9e6442a02a 2472 case LORAMAC_STATUS_FREQ_AND_DR_INVALID: {
Shaun Nelson 49:8b9e6442a02a 2473 status &= 0xFC;
Shaun Nelson 49:8b9e6442a02a 2474 break;
Shaun Nelson 49:8b9e6442a02a 2475 }
Shaun Nelson 49:8b9e6442a02a 2476 default: {
Shaun Nelson 49:8b9e6442a02a 2477 status &= 0xFC;
Shaun Nelson 49:8b9e6442a02a 2478 break;
Shaun Nelson 49:8b9e6442a02a 2479 }
Shaun Nelson 49:8b9e6442a02a 2480 }
Shaun Nelson 49:8b9e6442a02a 2481 }
Shaun Nelson 49:8b9e6442a02a 2482 LoRaMacState &= ~MAC_TX_CONFIG;
mluis 2:14a5d6ad92d5 2483 #endif
Shaun Nelson 49:8b9e6442a02a 2484 AddMacCommand(MOTE_MAC_NEW_CHANNEL_ANS, status, 0);
Shaun Nelson 49:8b9e6442a02a 2485 } break;
Shaun Nelson 49:8b9e6442a02a 2486 case SRV_MAC_RX_TIMING_SETUP_REQ: {
Shaun Nelson 49:8b9e6442a02a 2487 uint8_t delay = payload[macIndex++] & 0x0F;
Shaun Nelson 49:8b9e6442a02a 2488
Shaun Nelson 49:8b9e6442a02a 2489 if (delay == 0) {
Shaun Nelson 49:8b9e6442a02a 2490 delay++;
mluis 0:91d1a7783bb9 2491 }
Shaun Nelson 49:8b9e6442a02a 2492 ReceiveDelay1 = delay * 1e6;
Shaun Nelson 49:8b9e6442a02a 2493 ReceiveDelay2 = ReceiveDelay1 + 1e6;
Shaun Nelson 49:8b9e6442a02a 2494 AddMacCommand(MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0);
Shaun Nelson 49:8b9e6442a02a 2495 } break;
Shaun Nelson 49:8b9e6442a02a 2496 default:
Shaun Nelson 49:8b9e6442a02a 2497 // Unknown command. ABORT MAC commands processing
Shaun Nelson 49:8b9e6442a02a 2498 return;
mluis 0:91d1a7783bb9 2499 }
Shaun Nelson 49:8b9e6442a02a 2500 }
Shaun Nelson 49:8b9e6442a02a 2501
Shaun Nelson 49:8b9e6442a02a 2502 // Process accumulated Link ADR channel mask changes
Shaun Nelson 49:8b9e6442a02a 2503 if (validLinkAdrCmds > 0) {
Shaun Nelson 49:8b9e6442a02a 2504 uint8_t drOkCounter = 0;
Shaun Nelson 49:8b9e6442a02a 2505 uint8_t status = 0x07;
Shaun Nelson 49:8b9e6442a02a 2506
Shaun Nelson 49:8b9e6442a02a 2507 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2508 for (uint8_t i = 0; i < 6; i++) {
Shaun Nelson 49:8b9e6442a02a 2509 for (uint8_t j = 0; j < 16; j++) {
Shaun Nelson 49:8b9e6442a02a 2510 if ((channelsMask[i] & (1 << j)) != 0) {
Shaun Nelson 49:8b9e6442a02a 2511 if ((Channels[i * 16 + j].Frequency == 0)) {
Shaun Nelson 49:8b9e6442a02a 2512 status &= 0xFE; // Channel mask KO
Shaun Nelson 49:8b9e6442a02a 2513 break;
Shaun Nelson 49:8b9e6442a02a 2514 }
Shaun Nelson 49:8b9e6442a02a 2515 else if ((datarate >= Channels[i * 16 + j].DrRange.Fields.Min) &&
Shaun Nelson 49:8b9e6442a02a 2516 (datarate <= Channels[i * 16 + j].DrRange.Fields.Max)) {
Shaun Nelson 49:8b9e6442a02a 2517 drOkCounter++;
Shaun Nelson 49:8b9e6442a02a 2518 }
snelson 11:507de2ecd2b3 2519 }
Shaun Nelson 49:8b9e6442a02a 2520 }
Shaun Nelson 49:8b9e6442a02a 2521 }
Shaun Nelson 49:8b9e6442a02a 2522
Shaun Nelson 49:8b9e6442a02a 2523 if (drOkCounter == 0) {
Shaun Nelson 49:8b9e6442a02a 2524 status &= 0xFD; // Datarate KO
Shaun Nelson 49:8b9e6442a02a 2525 }
Shaun Nelson 49:8b9e6442a02a 2526
Shaun Nelson 49:8b9e6442a02a 2527 if ((CountNbEnabled125kHzChannels(channelsMask) > 0) &&
Shaun Nelson 49:8b9e6442a02a 2528 (CountNbEnabled125kHzChannels(channelsMask) < HYBRD_CHNLS_MIN)) {
Shaun Nelson 49:8b9e6442a02a 2529 status &= 0xFE; // Channel mask KO
Shaun Nelson 49:8b9e6442a02a 2530 }
Shaun Nelson 49:8b9e6442a02a 2531
Shaun Nelson 49:8b9e6442a02a 2532 #if defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2533 if (ValidateChannelMask(channelsMask) == false) {
Shaun Nelson 49:8b9e6442a02a 2534 status &= 0xFE; // Channel mask KO
Shaun Nelson 49:8b9e6442a02a 2535 }
snelson 11:507de2ecd2b3 2536 #endif
snelson 11:507de2ecd2b3 2537
snelson 11:507de2ecd2b3 2538 #endif
Shaun Nelson 49:8b9e6442a02a 2539 if ((status & 0x07) == 0x07) {
Shaun Nelson 49:8b9e6442a02a 2540 ChannelsDatarate = datarate;
Shaun Nelson 49:8b9e6442a02a 2541 ChannelsDefaultDatarate = datarate;
Shaun Nelson 49:8b9e6442a02a 2542 ChannelsTxPower = txPower;
Shaun Nelson 49:8b9e6442a02a 2543
Shaun Nelson 49:8b9e6442a02a 2544 ChannelsMask[0] = channelsMask[0];
Shaun Nelson 49:8b9e6442a02a 2545 ChannelsMask[1] = channelsMask[1];
Shaun Nelson 49:8b9e6442a02a 2546 ChannelsMask[2] = channelsMask[2];
Shaun Nelson 49:8b9e6442a02a 2547 ChannelsMask[3] = channelsMask[3];
Shaun Nelson 49:8b9e6442a02a 2548 ChannelsMask[4] = channelsMask[4];
Shaun Nelson 49:8b9e6442a02a 2549 ChannelsMask[5] = channelsMask[5];
Shaun Nelson 49:8b9e6442a02a 2550
Shaun Nelson 49:8b9e6442a02a 2551 ChannelsNbRep = nbRep;
Shaun Nelson 49:8b9e6442a02a 2552
Shaun Nelson 49:8b9e6442a02a 2553 // Clear remaining channels mask
Shaun Nelson 49:8b9e6442a02a 2554 memcpy1((uint8_t*)ChannelsMaskRemaining, (uint8_t*)ChannelsMask, 10);
mluis 2:14a5d6ad92d5 2555 }
Shaun Nelson 49:8b9e6442a02a 2556 // Channel Mask KO
Shaun Nelson 49:8b9e6442a02a 2557 else {
Shaun Nelson 49:8b9e6442a02a 2558 // Update the last Link ADR status with channel mask KO
Shaun Nelson 49:8b9e6442a02a 2559 if ((LinkAdrMacCmdBufferIndex + 1) < LORA_MAC_COMMAND_MAX_LENGTH)
Shaun Nelson 49:8b9e6442a02a 2560 MacCommandsBuffer[LinkAdrMacCmdBufferIndex + 1] &= status;
mluis 2:14a5d6ad92d5 2561 }
Shaun Nelson 49:8b9e6442a02a 2562 }
mluis 0:91d1a7783bb9 2563 }
mluis 0:91d1a7783bb9 2564
Shaun Nelson 49:8b9e6442a02a 2565 LoRaMacStatus_t Send(LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uint16_t fBufferSize) {
Shaun Nelson 49:8b9e6442a02a 2566 LoRaMacFrameCtrl_t fCtrl;
Shaun Nelson 49:8b9e6442a02a 2567 LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 2568
Shaun Nelson 49:8b9e6442a02a 2569 fCtrl.Value = 0;
Shaun Nelson 49:8b9e6442a02a 2570 fCtrl.Bits.FOptsLen = 0;
Shaun Nelson 49:8b9e6442a02a 2571 fCtrl.Bits.FPending = 0;
Shaun Nelson 49:8b9e6442a02a 2572 fCtrl.Bits.Ack = false;
Shaun Nelson 49:8b9e6442a02a 2573 fCtrl.Bits.AdrAckReq = false;
Shaun Nelson 49:8b9e6442a02a 2574 fCtrl.Bits.Adr = AdrCtrlOn;
Shaun Nelson 49:8b9e6442a02a 2575
Shaun Nelson 49:8b9e6442a02a 2576 // Prepare the frame
Shaun Nelson 49:8b9e6442a02a 2577 status = PrepareFrame(macHdr, &fCtrl, fPort, fBuffer, fBufferSize);
Shaun Nelson 49:8b9e6442a02a 2578
Shaun Nelson 49:8b9e6442a02a 2579 // Validate status
Shaun Nelson 49:8b9e6442a02a 2580 if (status != LORAMAC_STATUS_OK) {
Shaun Nelson 49:8b9e6442a02a 2581 return status;
Shaun Nelson 49:8b9e6442a02a 2582 }
Shaun Nelson 49:8b9e6442a02a 2583
Shaun Nelson 49:8b9e6442a02a 2584 // Reset confirm parameters
Shaun Nelson 49:8b9e6442a02a 2585 McpsConfirm.NbRetries = 0;
Shaun Nelson 49:8b9e6442a02a 2586 McpsConfirm.AckReceived = false;
Shaun Nelson 49:8b9e6442a02a 2587 McpsConfirm.UpLinkCounter = UpLinkCounter;
Shaun Nelson 49:8b9e6442a02a 2588
Shaun Nelson 49:8b9e6442a02a 2589 status = ScheduleTx();
Shaun Nelson 49:8b9e6442a02a 2590
Shaun Nelson 49:8b9e6442a02a 2591 return status;
mluis 2:14a5d6ad92d5 2592 }
mluis 2:14a5d6ad92d5 2593
Shaun Nelson 49:8b9e6442a02a 2594 static LoRaMacStatus_t ScheduleTx() {
Shaun Nelson 49:8b9e6442a02a 2595 TimerTime_t dutyCycleTimeOff = 0;
Shaun Nelson 49:8b9e6442a02a 2596
Shaun Nelson 49:8b9e6442a02a 2597 // Check if the device is off
Shaun Nelson 49:8b9e6442a02a 2598 if (MaxDCycle == 255) {
Shaun Nelson 49:8b9e6442a02a 2599 return LORAMAC_STATUS_DEVICE_OFF;
Shaun Nelson 49:8b9e6442a02a 2600 }
Shaun Nelson 49:8b9e6442a02a 2601 if (MaxDCycle == 0) {
Shaun Nelson 49:8b9e6442a02a 2602 AggregatedTimeOff = 0;
Shaun Nelson 49:8b9e6442a02a 2603 }
Shaun Nelson 49:8b9e6442a02a 2604
Shaun Nelson 49:8b9e6442a02a 2605 CalculateBackOff(LastTxChannel);
Shaun Nelson 49:8b9e6442a02a 2606
Shaun Nelson 49:8b9e6442a02a 2607 // Select channel
Shaun Nelson 49:8b9e6442a02a 2608 while (SetNextChannel(&dutyCycleTimeOff) == false) {
Shaun Nelson 49:8b9e6442a02a 2609 // Set the default datarate
Shaun Nelson 49:8b9e6442a02a 2610 ChannelsDatarate = ChannelsDefaultDatarate;
Shaun Nelson 49:8b9e6442a02a 2611
Shaun Nelson 49:8b9e6442a02a 2612 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 2613 // Re-enable default channels LC1, LC2, LC3
Shaun Nelson 49:8b9e6442a02a 2614 ChannelsMask[0] = ChannelsMask[0] | (LC(1) + LC(2) + LC(3));
mluis 2:14a5d6ad92d5 2615 #endif
Shaun Nelson 49:8b9e6442a02a 2616 }
Shaun Nelson 49:8b9e6442a02a 2617
Shaun Nelson 49:8b9e6442a02a 2618 // Schedule transmission of frame
Shaun Nelson 49:8b9e6442a02a 2619 if (dutyCycleTimeOff == 0) {
Shaun Nelson 49:8b9e6442a02a 2620 // Try to send now
Shaun Nelson 49:8b9e6442a02a 2621 return SendFrameOnChannel(Channels[Channel]);
Shaun Nelson 49:8b9e6442a02a 2622 }
Shaun Nelson 49:8b9e6442a02a 2623 else {
Shaun Nelson 49:8b9e6442a02a 2624 // Send later - prepare timer
Shaun Nelson 49:8b9e6442a02a 2625 LoRaMacState |= MAC_TX_DELAYED;
Shaun Nelson 49:8b9e6442a02a 2626 TimerSetValue(&TxDelayedTimer, dutyCycleTimeOff);
Shaun Nelson 49:8b9e6442a02a 2627 TimerStart(&TxDelayedTimer);
mluis 0:91d1a7783bb9 2628
mluis 2:14a5d6ad92d5 2629 return LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2630 }
mluis 0:91d1a7783bb9 2631 }
mluis 0:91d1a7783bb9 2632
Shaun Nelson 49:8b9e6442a02a 2633 static void CalculateBackOff(uint8_t channel) {
Shaun Nelson 49:8b9e6442a02a 2634 uint16_t dutyCycle = Bands[Channels[channel].Band].DCycle;
Shaun Nelson 49:8b9e6442a02a 2635
Shaun Nelson 49:8b9e6442a02a 2636 if (IsLoRaMacNetworkJoined == false) {
Shaun Nelson 49:8b9e6442a02a 2637 #if defined(USE_BAND_868) || defined(USE_BAND_433) || defined(USE_BAND_780)
Shaun Nelson 49:8b9e6442a02a 2638 dutyCycle = JOIN_DC;
Shaun Nelson 49:8b9e6442a02a 2639 #endif
Shaun Nelson 49:8b9e6442a02a 2640 }
Shaun Nelson 49:8b9e6442a02a 2641
Shaun Nelson 49:8b9e6442a02a 2642 // Update Band Time OFF
Shaun Nelson 49:8b9e6442a02a 2643 if (DutyCycleOn == true) {
Shaun Nelson 49:8b9e6442a02a 2644 Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir;
Shaun Nelson 49:8b9e6442a02a 2645 }
Shaun Nelson 49:8b9e6442a02a 2646 else {
Shaun Nelson 49:8b9e6442a02a 2647 Bands[Channels[channel].Band].TimeOff = 0;
Shaun Nelson 49:8b9e6442a02a 2648 }
Shaun Nelson 49:8b9e6442a02a 2649 // Update Aggregated Time OFF
Shaun Nelson 49:8b9e6442a02a 2650 AggregatedTimeOff = AggregatedTimeOff + (TxTimeOnAir * AggregatedDCycle - TxTimeOnAir);
Shaun Nelson 49:8b9e6442a02a 2651 }
Shaun Nelson 49:8b9e6442a02a 2652
Shaun Nelson 49:8b9e6442a02a 2653 LoRaMacStatus_t PrepareFrame(LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort,
Shaun Nelson 49:8b9e6442a02a 2654 void* fBuffer, uint16_t fBufferSize) {
Shaun Nelson 49:8b9e6442a02a 2655 uint16_t i;
Shaun Nelson 49:8b9e6442a02a 2656 uint8_t pktHeaderLen = 0;
Shaun Nelson 49:8b9e6442a02a 2657 uint32_t mic = 0;
Shaun Nelson 49:8b9e6442a02a 2658 const void* payload = fBuffer;
Shaun Nelson 49:8b9e6442a02a 2659 uint8_t payloadSize = fBufferSize;
Shaun Nelson 49:8b9e6442a02a 2660 uint8_t framePort = fPort;
Shaun Nelson 49:8b9e6442a02a 2661
Shaun Nelson 49:8b9e6442a02a 2662 LoRaMacBufferPktLen = 0;
Shaun Nelson 49:8b9e6442a02a 2663
Shaun Nelson 49:8b9e6442a02a 2664 NodeAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 2665
Shaun Nelson 49:8b9e6442a02a 2666 if (fBuffer == NULL) {
Shaun Nelson 49:8b9e6442a02a 2667 fBufferSize = 0;
Shaun Nelson 49:8b9e6442a02a 2668 }
Shaun Nelson 49:8b9e6442a02a 2669
Shaun Nelson 49:8b9e6442a02a 2670 LoRaMacBuffer[pktHeaderLen++] = macHdr->Value;
Shaun Nelson 49:8b9e6442a02a 2671
Shaun Nelson 49:8b9e6442a02a 2672 switch (macHdr->Bits.MType) {
Shaun Nelson 49:8b9e6442a02a 2673 case FRAME_TYPE_JOIN_REQ:
Shaun Nelson 49:8b9e6442a02a 2674 RxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME;
Shaun Nelson 49:8b9e6442a02a 2675 RxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME;
Shaun Nelson 49:8b9e6442a02a 2676
Shaun Nelson 49:8b9e6442a02a 2677 LoRaMacBufferPktLen = pktHeaderLen;
Shaun Nelson 49:8b9e6442a02a 2678
Shaun Nelson 49:8b9e6442a02a 2679 memcpyr(LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8);
Shaun Nelson 49:8b9e6442a02a 2680 LoRaMacBufferPktLen += 8;
Shaun Nelson 49:8b9e6442a02a 2681 memcpyr(LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacDevEui, 8);
Shaun Nelson 49:8b9e6442a02a 2682 LoRaMacBufferPktLen += 8;
Shaun Nelson 49:8b9e6442a02a 2683
Shaun Nelson 49:8b9e6442a02a 2684 LoRaMacDevNonce = Radio.Random();
Shaun Nelson 49:8b9e6442a02a 2685
Shaun Nelson 49:8b9e6442a02a 2686 LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2687 LoRaMacBuffer[LoRaMacBufferPktLen++] = (LoRaMacDevNonce >> 8) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2688
Shaun Nelson 49:8b9e6442a02a 2689 LoRaMacJoinComputeMic(LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic);
Shaun Nelson 49:8b9e6442a02a 2690
Shaun Nelson 49:8b9e6442a02a 2691 LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2692 LoRaMacBuffer[LoRaMacBufferPktLen++] = (mic >> 8) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2693 LoRaMacBuffer[LoRaMacBufferPktLen++] = (mic >> 16) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2694 LoRaMacBuffer[LoRaMacBufferPktLen++] = (mic >> 24) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2695
Shaun Nelson 49:8b9e6442a02a 2696 break;
Shaun Nelson 49:8b9e6442a02a 2697 case FRAME_TYPE_DATA_CONFIRMED_UP:
Shaun Nelson 49:8b9e6442a02a 2698 NodeAckRequested = true;
Shaun Nelson 49:8b9e6442a02a 2699 // Intentional falltrough
Shaun Nelson 49:8b9e6442a02a 2700 case FRAME_TYPE_DATA_UNCONFIRMED_UP:
Shaun Nelson 49:8b9e6442a02a 2701 if (IsLoRaMacNetworkJoined == false) {
Shaun Nelson 49:8b9e6442a02a 2702 return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined
Shaun Nelson 49:8b9e6442a02a 2703 // yet
Shaun Nelson 49:8b9e6442a02a 2704 }
Shaun Nelson 49:8b9e6442a02a 2705
Shaun Nelson 49:8b9e6442a02a 2706 fCtrl->Bits.AdrAckReq = AdrNextDr(fCtrl->Bits.Adr, true, &ChannelsDatarate, &ChannelsTxPower);
Shaun Nelson 49:8b9e6442a02a 2707
Shaun Nelson 49:8b9e6442a02a 2708 if (ValidatePayloadLength(fBufferSize, ChannelsDatarate, MacCommandsBufferIndex) == false) {
Shaun Nelson 49:8b9e6442a02a 2709 return LORAMAC_STATUS_LENGTH_ERROR;
Shaun Nelson 49:8b9e6442a02a 2710 }
Shaun Nelson 49:8b9e6442a02a 2711
Shaun Nelson 49:8b9e6442a02a 2712 RxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME;
Shaun Nelson 49:8b9e6442a02a 2713 RxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME;
Shaun Nelson 49:8b9e6442a02a 2714
Shaun Nelson 49:8b9e6442a02a 2715 if (SrvAckRequested == true) {
Shaun Nelson 49:8b9e6442a02a 2716 SrvAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 2717 fCtrl->Bits.Ack = 1;
Shaun Nelson 49:8b9e6442a02a 2718 }
Shaun Nelson 49:8b9e6442a02a 2719
Shaun Nelson 49:8b9e6442a02a 2720 LoRaMacBuffer[pktHeaderLen++] = (LoRaMacDevAddr)&0xFF;
Shaun Nelson 49:8b9e6442a02a 2721 LoRaMacBuffer[pktHeaderLen++] = (LoRaMacDevAddr >> 8) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2722 LoRaMacBuffer[pktHeaderLen++] = (LoRaMacDevAddr >> 16) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2723 LoRaMacBuffer[pktHeaderLen++] = (LoRaMacDevAddr >> 24) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2724
Shaun Nelson 49:8b9e6442a02a 2725 LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value;
Shaun Nelson 49:8b9e6442a02a 2726
Shaun Nelson 49:8b9e6442a02a 2727 LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2728 LoRaMacBuffer[pktHeaderLen++] = (UpLinkCounter >> 8) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2729
Shaun Nelson 49:8b9e6442a02a 2730 // Copy the MAC commands which must be re-send into the MAC command buffer
Shaun Nelson 49:8b9e6442a02a 2731 memcpy1(&MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat,
Shaun Nelson 49:8b9e6442a02a 2732 MacCommandsBufferToRepeatIndex);
Shaun Nelson 49:8b9e6442a02a 2733 MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex;
Shaun Nelson 49:8b9e6442a02a 2734
Shaun Nelson 49:8b9e6442a02a 2735 if ((payload != NULL) && (payloadSize > 0)) {
Shaun Nelson 49:8b9e6442a02a 2736 if ((MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH) &&
Shaun Nelson 49:8b9e6442a02a 2737 (MacCommandsInNextTx == true)) {
Shaun Nelson 49:8b9e6442a02a 2738 fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
Shaun Nelson 49:8b9e6442a02a 2739
Shaun Nelson 49:8b9e6442a02a 2740 // Update FCtrl field with new value of OptionsLength
Shaun Nelson 49:8b9e6442a02a 2741 LoRaMacBuffer[0x05] = fCtrl->Value;
Shaun Nelson 49:8b9e6442a02a 2742 for (i = 0; i < MacCommandsBufferIndex; i++) {
Shaun Nelson 49:8b9e6442a02a 2743 LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
Shaun Nelson 49:8b9e6442a02a 2744 }
mluis 4:37c12dbc8dc7 2745 }
Shaun Nelson 49:8b9e6442a02a 2746 }
Shaun Nelson 49:8b9e6442a02a 2747 else {
Shaun Nelson 49:8b9e6442a02a 2748 if ((MacCommandsBufferIndex > 0) && (MacCommandsInNextTx)) {
Shaun Nelson 49:8b9e6442a02a 2749 payloadSize = MacCommandsBufferIndex;
Shaun Nelson 49:8b9e6442a02a 2750 payload = MacCommandsBuffer;
Shaun Nelson 49:8b9e6442a02a 2751 framePort = 0;
mluis 2:14a5d6ad92d5 2752 }
Shaun Nelson 49:8b9e6442a02a 2753 }
Shaun Nelson 49:8b9e6442a02a 2754 MacCommandsInNextTx = false;
Shaun Nelson 49:8b9e6442a02a 2755 // Store MAC commands which must be re-send in case the device does not
Shaun Nelson 49:8b9e6442a02a 2756 // receive a downlink anymore
Shaun Nelson 49:8b9e6442a02a 2757 MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat(
Shaun Nelson 49:8b9e6442a02a 2758 MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat);
Shaun Nelson 49:8b9e6442a02a 2759 if (MacCommandsBufferToRepeatIndex > 0) {
Shaun Nelson 49:8b9e6442a02a 2760 MacCommandsInNextTx = true;
Shaun Nelson 49:8b9e6442a02a 2761 }
Shaun Nelson 49:8b9e6442a02a 2762 MacCommandsBufferIndex = 0;
Shaun Nelson 49:8b9e6442a02a 2763
Shaun Nelson 49:8b9e6442a02a 2764 if ((payload != NULL) && (payloadSize > 0)) {
Shaun Nelson 49:8b9e6442a02a 2765 LoRaMacBuffer[pktHeaderLen++] = framePort;
Shaun Nelson 49:8b9e6442a02a 2766
Shaun Nelson 49:8b9e6442a02a 2767 if (framePort == 0) {
Shaun Nelson 49:8b9e6442a02a 2768 LoRaMacPayloadEncrypt((uint8_t*)payload, payloadSize, LoRaMacNwkSKey, LoRaMacDevAddr,
Shaun Nelson 49:8b9e6442a02a 2769 UP_LINK, UpLinkCounter, LoRaMacPayload);
mluis 2:14a5d6ad92d5 2770 }
Shaun Nelson 49:8b9e6442a02a 2771 else {
Shaun Nelson 49:8b9e6442a02a 2772 LoRaMacPayloadEncrypt((uint8_t*)payload, payloadSize, LoRaMacAppSKey, LoRaMacDevAddr,
Shaun Nelson 49:8b9e6442a02a 2773 UP_LINK, UpLinkCounter, LoRaMacPayload);
mluis 2:14a5d6ad92d5 2774 }
Shaun Nelson 49:8b9e6442a02a 2775 memcpy1(LoRaMacBuffer + pktHeaderLen, LoRaMacPayload, payloadSize);
Shaun Nelson 49:8b9e6442a02a 2776 }
Shaun Nelson 49:8b9e6442a02a 2777 LoRaMacBufferPktLen = pktHeaderLen + payloadSize;
Shaun Nelson 49:8b9e6442a02a 2778
Shaun Nelson 49:8b9e6442a02a 2779 LoRaMacComputeMic(LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK,
Shaun Nelson 49:8b9e6442a02a 2780 UpLinkCounter, &mic);
Shaun Nelson 49:8b9e6442a02a 2781
Shaun Nelson 49:8b9e6442a02a 2782 LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2783 LoRaMacBuffer[LoRaMacBufferPktLen + 1] = (mic >> 8) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2784 LoRaMacBuffer[LoRaMacBufferPktLen + 2] = (mic >> 16) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2785 LoRaMacBuffer[LoRaMacBufferPktLen + 3] = (mic >> 24) & 0xFF;
Shaun Nelson 49:8b9e6442a02a 2786
Shaun Nelson 49:8b9e6442a02a 2787 LoRaMacBufferPktLen += LORAMAC_MFR_LEN;
Shaun Nelson 49:8b9e6442a02a 2788
Shaun Nelson 49:8b9e6442a02a 2789 break;
Shaun Nelson 49:8b9e6442a02a 2790 case FRAME_TYPE_PROPRIETARY:
Shaun Nelson 49:8b9e6442a02a 2791 if ((fBuffer != NULL) && (fBufferSize > 0)) {
Shaun Nelson 49:8b9e6442a02a 2792 memcpy1(LoRaMacBuffer + pktHeaderLen, (uint8_t*)fBuffer, fBufferSize);
Shaun Nelson 49:8b9e6442a02a 2793 LoRaMacBufferPktLen = pktHeaderLen + fBufferSize;
Shaun Nelson 49:8b9e6442a02a 2794 }
Shaun Nelson 49:8b9e6442a02a 2795 break;
Shaun Nelson 49:8b9e6442a02a 2796 default:
Shaun Nelson 49:8b9e6442a02a 2797 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Shaun Nelson 49:8b9e6442a02a 2798 }
Shaun Nelson 49:8b9e6442a02a 2799
Shaun Nelson 49:8b9e6442a02a 2800 return LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2801 }
Shaun Nelson 49:8b9e6442a02a 2802
Shaun Nelson 49:8b9e6442a02a 2803 LoRaMacStatus_t SendFrameOnChannel(ChannelParams_t channel) {
Shaun Nelson 49:8b9e6442a02a 2804 int8_t datarate = Datarates[ChannelsDatarate];
Shaun Nelson 49:8b9e6442a02a 2805 int8_t txPowerIndex = 0;
Shaun Nelson 49:8b9e6442a02a 2806 int8_t txPower = 0;
Shaun Nelson 49:8b9e6442a02a 2807
Shaun Nelson 49:8b9e6442a02a 2808 txPowerIndex = LimitTxPower(ChannelsTxPower);
Shaun Nelson 49:8b9e6442a02a 2809 txPower = TxPowers[txPowerIndex];
Shaun Nelson 49:8b9e6442a02a 2810
Shaun Nelson 49:8b9e6442a02a 2811 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
Shaun Nelson 49:8b9e6442a02a 2812 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
Shaun Nelson 49:8b9e6442a02a 2813 McpsConfirm.Datarate = ChannelsDatarate;
Shaun Nelson 49:8b9e6442a02a 2814 McpsConfirm.TxPower = txPowerIndex;
Shaun Nelson 49:8b9e6442a02a 2815
Shaun Nelson 49:8b9e6442a02a 2816 Radio.SetChannel(channel.Frequency);
Shaun Nelson 49:8b9e6442a02a 2817
Shaun Nelson 49:8b9e6442a02a 2818 // LOG("Radio TxPower=%u\r\n", txPower);
Shaun Nelson 49:8b9e6442a02a 2819 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 2820 if (ChannelsDatarate == DR_7) { // High Speed FSK channel
Shaun Nelson 49:8b9e6442a02a 2821 Radio.SetMaxPayloadLength(MODEM_FSK, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2822 Radio.SetTxConfig(MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, 0, 0, false,
Shaun Nelson 49:8b9e6442a02a 2823 3e6);
Shaun Nelson 49:8b9e6442a02a 2824 TxTimeOnAir = Radio.TimeOnAir(MODEM_FSK, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2825 }
Shaun Nelson 49:8b9e6442a02a 2826 else if (ChannelsDatarate == DR_6) { // High speed LoRa channel
Shaun Nelson 49:8b9e6442a02a 2827 Radio.SetMaxPayloadLength(MODEM_LORA, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2828 Radio.SetTxConfig(MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, 0, 0, false, 3e6);
Shaun Nelson 49:8b9e6442a02a 2829 TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2830 }
Shaun Nelson 49:8b9e6442a02a 2831 else { // Normal LoRa channel
Shaun Nelson 49:8b9e6442a02a 2832 Radio.SetMaxPayloadLength(MODEM_LORA, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2833 Radio.SetTxConfig(MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6);
Shaun Nelson 49:8b9e6442a02a 2834 TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2835 }
Shaun Nelson 49:8b9e6442a02a 2836 #elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2837 Radio.SetMaxPayloadLength(MODEM_LORA, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2838 if (ChannelsDatarate >= DR_4) { // High speed LoRa channel BW500 kHz
Shaun Nelson 49:8b9e6442a02a 2839 Radio.SetTxConfig(MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e6);
Shaun Nelson 49:8b9e6442a02a 2840 TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2841 }
Shaun Nelson 49:8b9e6442a02a 2842 else { // Normal LoRa channel
Shaun Nelson 49:8b9e6442a02a 2843 Radio.SetTxConfig(MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6);
Shaun Nelson 49:8b9e6442a02a 2844 TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2845 }
Shaun Nelson 49:8b9e6442a02a 2846 #else
Shaun Nelson 49:8b9e6442a02a 2847 #error "Please define a frequency band in the compiler options."
Shaun Nelson 49:8b9e6442a02a 2848 #endif
Shaun Nelson 49:8b9e6442a02a 2849
Shaun Nelson 49:8b9e6442a02a 2850 // Store the time on air
Shaun Nelson 49:8b9e6442a02a 2851 McpsConfirm.TxTimeOnAir = TxTimeOnAir;
Shaun Nelson 49:8b9e6442a02a 2852 MlmeConfirm.TxTimeOnAir = TxTimeOnAir;
Shaun Nelson 49:8b9e6442a02a 2853
Shaun Nelson 49:8b9e6442a02a 2854 // Starts the MAC layer status check timer
Shaun Nelson 49:8b9e6442a02a 2855 TimerSetValue(&MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT);
Shaun Nelson 49:8b9e6442a02a 2856 TimerStart(&MacStateCheckTimer);
Shaun Nelson 49:8b9e6442a02a 2857
Shaun Nelson 49:8b9e6442a02a 2858 // Send now
Shaun Nelson 49:8b9e6442a02a 2859 Radio.Send(LoRaMacBuffer, LoRaMacBufferPktLen);
Shaun Nelson 49:8b9e6442a02a 2860
Shaun Nelson 49:8b9e6442a02a 2861 LoRaMacState |= MAC_TX_RUNNING;
Shaun Nelson 49:8b9e6442a02a 2862
Shaun Nelson 49:8b9e6442a02a 2863 return LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 2864 }
Shaun Nelson 49:8b9e6442a02a 2865
Shaun Nelson 49:8b9e6442a02a 2866 LoRaMacStatus_t LoRaMacInitialization(LoRaMacPrimitives_t* primitives,
Shaun Nelson 49:8b9e6442a02a 2867 LoRaMacCallback_t* callbacks) {
Shaun Nelson 49:8b9e6442a02a 2868 if (primitives == NULL) {
Shaun Nelson 49:8b9e6442a02a 2869 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 2870 }
Shaun Nelson 49:8b9e6442a02a 2871
Shaun Nelson 49:8b9e6442a02a 2872 if ((primitives->MacMcpsConfirm == NULL) || (primitives->MacMcpsIndication == NULL) ||
Shaun Nelson 49:8b9e6442a02a 2873 (primitives->MacMlmeConfirm == NULL)) {
Shaun Nelson 49:8b9e6442a02a 2874 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 2875 }
Shaun Nelson 49:8b9e6442a02a 2876
Shaun Nelson 49:8b9e6442a02a 2877 LoRaMacPrimitives = primitives;
Shaun Nelson 49:8b9e6442a02a 2878 LoRaMacCallbacks = callbacks;
Shaun Nelson 49:8b9e6442a02a 2879
Shaun Nelson 49:8b9e6442a02a 2880 LoRaMacFlags.Value = 0;
Shaun Nelson 49:8b9e6442a02a 2881
Shaun Nelson 49:8b9e6442a02a 2882 LoRaMacDeviceClass = CLASS_A;
Shaun Nelson 49:8b9e6442a02a 2883
Shaun Nelson 49:8b9e6442a02a 2884 UpLinkCounter = 1;
Shaun Nelson 49:8b9e6442a02a 2885 DownLinkCounter = 0;
Shaun Nelson 49:8b9e6442a02a 2886 AdrAckCounter = 0;
Shaun Nelson 49:8b9e6442a02a 2887
Shaun Nelson 49:8b9e6442a02a 2888 ChannelsNbRepCounter = 0;
Shaun Nelson 49:8b9e6442a02a 2889
Shaun Nelson 49:8b9e6442a02a 2890 AckTimeoutRetries = 1;
Shaun Nelson 49:8b9e6442a02a 2891 AckTimeoutRetriesCounter = 1;
Shaun Nelson 49:8b9e6442a02a 2892 AckTimeoutRetry = false;
Shaun Nelson 49:8b9e6442a02a 2893
Shaun Nelson 49:8b9e6442a02a 2894 MaxDCycle = 0;
Shaun Nelson 49:8b9e6442a02a 2895 AggregatedDCycle = 1;
Shaun Nelson 49:8b9e6442a02a 2896
Shaun Nelson 49:8b9e6442a02a 2897 MacCommandsBufferIndex = 0;
Shaun Nelson 49:8b9e6442a02a 2898 MacCommandsBufferToRepeatIndex = 0;
Shaun Nelson 49:8b9e6442a02a 2899
Shaun Nelson 49:8b9e6442a02a 2900 IsRxWindowsEnabled = true;
Shaun Nelson 49:8b9e6442a02a 2901
Shaun Nelson 49:8b9e6442a02a 2902 RepeaterSupport = false;
Shaun Nelson 49:8b9e6442a02a 2903 IsRxWindowsEnabled = true;
Shaun Nelson 49:8b9e6442a02a 2904 IsLoRaMacNetworkJoined = false;
Shaun Nelson 49:8b9e6442a02a 2905 LoRaMacState = MAC_IDLE;
Shaun Nelson 49:8b9e6442a02a 2906
Shaun Nelson 49:8b9e6442a02a 2907 NodeAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 2908 SrvAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 2909 MacCommandsInNextTx = false;
Shaun Nelson 49:8b9e6442a02a 2910
Shaun Nelson 49:8b9e6442a02a 2911 #if defined(USE_BAND_433)
Shaun Nelson 49:8b9e6442a02a 2912 ChannelsMask[0] = LC(1) + LC(2) + LC(3);
Shaun Nelson 49:8b9e6442a02a 2913 #elif defined(USE_BAND_780)
Shaun Nelson 49:8b9e6442a02a 2914 ChannelsMask[0] = LC(1) + LC(2) + LC(3);
Shaun Nelson 49:8b9e6442a02a 2915 #elif defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 2916 ChannelsMask[0] = LC(1) + LC(2) + LC(3);
Shaun Nelson 49:8b9e6442a02a 2917 #elif defined(USE_BAND_915)
Shaun Nelson 49:8b9e6442a02a 2918 ChannelsMask[0] = 0xFFFF;
Shaun Nelson 49:8b9e6442a02a 2919 ChannelsMask[1] = 0xFFFF;
Shaun Nelson 49:8b9e6442a02a 2920 ChannelsMask[2] = 0xFFFF;
Shaun Nelson 49:8b9e6442a02a 2921 ChannelsMask[3] = 0xFFFF;
Shaun Nelson 49:8b9e6442a02a 2922 ChannelsMask[4] = 0x00FF;
Shaun Nelson 49:8b9e6442a02a 2923 ChannelsMask[5] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2924
Shaun Nelson 49:8b9e6442a02a 2925 memcpy1((uint8_t*)ChannelsMaskRemaining, (uint8_t*)ChannelsMask, sizeof(ChannelsMask));
Shaun Nelson 49:8b9e6442a02a 2926 #elif defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2927 ChannelsMask[0] = 0x00FF;
Shaun Nelson 49:8b9e6442a02a 2928 ChannelsMask[1] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2929 ChannelsMask[2] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2930 ChannelsMask[3] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2931 ChannelsMask[4] = 0x0001;
Shaun Nelson 49:8b9e6442a02a 2932 ChannelsMask[5] = 0x0000;
Shaun Nelson 49:8b9e6442a02a 2933
Shaun Nelson 49:8b9e6442a02a 2934 memcpy1((uint8_t*)ChannelsMaskRemaining, (uint8_t*)ChannelsMask, sizeof(ChannelsMask));
Shaun Nelson 49:8b9e6442a02a 2935 #else
Shaun Nelson 49:8b9e6442a02a 2936 #error "Please define a frequency band in the compiler options."
Shaun Nelson 49:8b9e6442a02a 2937 #endif
Shaun Nelson 49:8b9e6442a02a 2938
Shaun Nelson 49:8b9e6442a02a 2939 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2940 // 125 kHz channels
Shaun Nelson 49:8b9e6442a02a 2941 for (uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++) {
Shaun Nelson 49:8b9e6442a02a 2942 Channels[i].Frequency = 902.3e6 + i * 200e3;
Shaun Nelson 49:8b9e6442a02a 2943 Channels[i].DrRange.Value = (DR_3 << 4) | DR_0;
Shaun Nelson 49:8b9e6442a02a 2944 Channels[i].Band = 0;
Shaun Nelson 49:8b9e6442a02a 2945 }
Shaun Nelson 49:8b9e6442a02a 2946 // 500 kHz channels
Shaun Nelson 49:8b9e6442a02a 2947 for (uint8_t i = LORA_MAX_NB_CHANNELS - 8; i < LORA_MAX_NB_CHANNELS; i++) {
Shaun Nelson 49:8b9e6442a02a 2948 Channels[i].Frequency = 903.0e6 + (i - (LORA_MAX_NB_CHANNELS - 8)) * 1.6e6;
Shaun Nelson 49:8b9e6442a02a 2949 Channels[i].DrRange.Value = (DR_4 << 4) | DR_4;
Shaun Nelson 49:8b9e6442a02a 2950 Channels[i].Band = 0;
Shaun Nelson 49:8b9e6442a02a 2951 }
Shaun Nelson 49:8b9e6442a02a 2952 #endif
Shaun Nelson 49:8b9e6442a02a 2953
Shaun Nelson 49:8b9e6442a02a 2954 ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
Shaun Nelson 49:8b9e6442a02a 2955 ChannelsDefaultDatarate = ChannelsDatarate = LORAMAC_DEFAULT_DATARATE;
Shaun Nelson 49:8b9e6442a02a 2956 ChannelsNbRep = 1;
Shaun Nelson 49:8b9e6442a02a 2957 ChannelsNbRepCounter = 0;
Shaun Nelson 49:8b9e6442a02a 2958
Shaun Nelson 49:8b9e6442a02a 2959 Rx2Channel.Frequency = 923300000;
Shaun Nelson 49:8b9e6442a02a 2960 Rx2Channel.Datarate = DR_8;
Shaun Nelson 49:8b9e6442a02a 2961 Rx1DrOffset = 0;
Shaun Nelson 49:8b9e6442a02a 2962
Shaun Nelson 49:8b9e6442a02a 2963 MaxDCycle = 0;
Shaun Nelson 49:8b9e6442a02a 2964 AggregatedDCycle = 1;
Shaun Nelson 49:8b9e6442a02a 2965 AggregatedLastTxDoneTime = 0;
Shaun Nelson 49:8b9e6442a02a 2966 AggregatedTimeOff = 0;
Shaun Nelson 49:8b9e6442a02a 2967
Shaun Nelson 49:8b9e6442a02a 2968 #if defined(USE_BAND_433)
Shaun Nelson 49:8b9e6442a02a 2969 DutyCycleOn = false;
Shaun Nelson 49:8b9e6442a02a 2970 #elif defined(USE_BAND_780)
Shaun Nelson 49:8b9e6442a02a 2971 DutyCycleOn = false;
Shaun Nelson 49:8b9e6442a02a 2972 #elif defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 2973 DutyCycleOn = true;
Shaun Nelson 49:8b9e6442a02a 2974 #elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 2975 DutyCycleOn = false;
Shaun Nelson 49:8b9e6442a02a 2976 #else
Shaun Nelson 49:8b9e6442a02a 2977 #error "Please define a frequency band in the compiler options."
mluis 4:37c12dbc8dc7 2978 #endif
Shaun Nelson 49:8b9e6442a02a 2979
Shaun Nelson 49:8b9e6442a02a 2980 MaxRxWindow = MAX_RX_WINDOW;
Shaun Nelson 49:8b9e6442a02a 2981 ReceiveDelay1 = RECEIVE_DELAY1;
Shaun Nelson 49:8b9e6442a02a 2982 ReceiveDelay2 = RECEIVE_DELAY2;
Shaun Nelson 49:8b9e6442a02a 2983 JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1;
Shaun Nelson 49:8b9e6442a02a 2984 JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2;
Shaun Nelson 49:8b9e6442a02a 2985
Shaun Nelson 49:8b9e6442a02a 2986 #if defined(USE_BAND_915)
Shaun Nelson 49:8b9e6442a02a 2987 NextJoinBlock = 0;
Shaun Nelson 49:8b9e6442a02a 2988 LastJoinBlock = -1;
Shaun Nelson 49:8b9e6442a02a 2989 JoinBlocksRemaining = 0xff;
Shaun Nelson 49:8b9e6442a02a 2990 Join500KHzRemaining = 0xff;
mluis 0:91d1a7783bb9 2991 #endif
Shaun Nelson 49:8b9e6442a02a 2992
Shaun Nelson 49:8b9e6442a02a 2993 LastJoinTxTime = 0;
Shaun Nelson 49:8b9e6442a02a 2994 JoinAggTimeOnAir = 0;
Shaun Nelson 49:8b9e6442a02a 2995
Shaun Nelson 49:8b9e6442a02a 2996 TimerInit(&MacStateCheckTimer, OnMacStateCheckTimerEvent);
Shaun Nelson 49:8b9e6442a02a 2997 TimerSetValue(&MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT);
Shaun Nelson 49:8b9e6442a02a 2998
Shaun Nelson 49:8b9e6442a02a 2999 TimerInit(&TxDelayedTimer, OnTxDelayedTimerEvent);
Shaun Nelson 49:8b9e6442a02a 3000 TimerInit(&RxWindowTimer1, OnRxWindow1TimerEvent);
Shaun Nelson 49:8b9e6442a02a 3001 TimerInit(&RxWindowTimer2, OnRxWindow2TimerEvent);
Shaun Nelson 49:8b9e6442a02a 3002 TimerInit(&AckTimeoutTimer, OnAckTimeoutTimerEvent);
Shaun Nelson 49:8b9e6442a02a 3003
Shaun Nelson 49:8b9e6442a02a 3004 // Initialize Radio driver
Shaun Nelson 49:8b9e6442a02a 3005 RadioEvents.TxDone = OnRadioTxDone;
Shaun Nelson 49:8b9e6442a02a 3006 RadioEvents.RxDone = OnRadioRxDone;
Shaun Nelson 49:8b9e6442a02a 3007 RadioEvents.RxError = OnRadioRxError;
Shaun Nelson 49:8b9e6442a02a 3008 RadioEvents.TxTimeout = OnRadioTxTimeout;
Shaun Nelson 49:8b9e6442a02a 3009 RadioEvents.RxTimeout = OnRadioRxTimeout;
Shaun Nelson 49:8b9e6442a02a 3010 Radio.Init(&RadioEvents);
Shaun Nelson 49:8b9e6442a02a 3011
Shaun Nelson 49:8b9e6442a02a 3012 // Random seed initialization
Shaun Nelson 49:8b9e6442a02a 3013 srand1(Radio.Random());
Shaun Nelson 49:8b9e6442a02a 3014
Shaun Nelson 49:8b9e6442a02a 3015 // Initialize channel index.
Shaun Nelson 49:8b9e6442a02a 3016 Channel = LORA_MAX_NB_CHANNELS;
Shaun Nelson 49:8b9e6442a02a 3017
Shaun Nelson 49:8b9e6442a02a 3018 PublicNetwork = true;
Shaun Nelson 49:8b9e6442a02a 3019 SetPublicNetwork(PublicNetwork);
Shaun Nelson 49:8b9e6442a02a 3020 Radio.Sleep();
Shaun Nelson 49:8b9e6442a02a 3021
Shaun Nelson 49:8b9e6442a02a 3022 return LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 3023 }
Shaun Nelson 49:8b9e6442a02a 3024
Shaun Nelson 49:8b9e6442a02a 3025 LoRaMacStatus_t LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t* txInfo) {
Shaun Nelson 49:8b9e6442a02a 3026 int8_t datarate = ChannelsDefaultDatarate;
Shaun Nelson 49:8b9e6442a02a 3027 uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
Shaun Nelson 49:8b9e6442a02a 3028
Shaun Nelson 49:8b9e6442a02a 3029 if (txInfo == NULL) {
Shaun Nelson 49:8b9e6442a02a 3030 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3031 }
Shaun Nelson 49:8b9e6442a02a 3032
Shaun Nelson 49:8b9e6442a02a 3033 AdrNextDr(AdrCtrlOn, false, &datarate, NULL);
Shaun Nelson 49:8b9e6442a02a 3034
Shaun Nelson 49:8b9e6442a02a 3035 if (RepeaterSupport == true) {
Shaun Nelson 49:8b9e6442a02a 3036 txInfo->CurrentPayloadSize = MaxPayloadOfDatarateRepeater[datarate];
Shaun Nelson 49:8b9e6442a02a 3037 }
Shaun Nelson 49:8b9e6442a02a 3038 else {
Shaun Nelson 49:8b9e6442a02a 3039 txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate];
Shaun Nelson 49:8b9e6442a02a 3040 }
Shaun Nelson 49:8b9e6442a02a 3041
Shaun Nelson 49:8b9e6442a02a 3042 if (txInfo->CurrentPayloadSize >= fOptLen) {
Shaun Nelson 49:8b9e6442a02a 3043 txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen;
Shaun Nelson 49:8b9e6442a02a 3044 }
Shaun Nelson 49:8b9e6442a02a 3045 else {
Shaun Nelson 49:8b9e6442a02a 3046 return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
Shaun Nelson 49:8b9e6442a02a 3047 }
Shaun Nelson 49:8b9e6442a02a 3048
Shaun Nelson 49:8b9e6442a02a 3049 if (ValidatePayloadLength(size, datarate, 0) == false) {
Shaun Nelson 49:8b9e6442a02a 3050 return LORAMAC_STATUS_LENGTH_ERROR;
Shaun Nelson 49:8b9e6442a02a 3051 }
Shaun Nelson 49:8b9e6442a02a 3052
Shaun Nelson 49:8b9e6442a02a 3053 if (ValidatePayloadLength(size, datarate, fOptLen) == false) {
Shaun Nelson 49:8b9e6442a02a 3054 return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
Shaun Nelson 49:8b9e6442a02a 3055 }
Shaun Nelson 49:8b9e6442a02a 3056
Shaun Nelson 49:8b9e6442a02a 3057 return LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 3058 }
Shaun Nelson 49:8b9e6442a02a 3059
Shaun Nelson 49:8b9e6442a02a 3060 LoRaMacStatus_t LoRaMacMibGetRequestConfirm(MibRequestConfirm_t* mibGet) {
Shaun Nelson 49:8b9e6442a02a 3061 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 3062
Shaun Nelson 49:8b9e6442a02a 3063 if (mibGet == NULL) {
Shaun Nelson 49:8b9e6442a02a 3064 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3065 }
Shaun Nelson 49:8b9e6442a02a 3066
Shaun Nelson 49:8b9e6442a02a 3067 switch (mibGet->Type) {
Shaun Nelson 49:8b9e6442a02a 3068 case MIB_DEVICE_CLASS: {
Shaun Nelson 49:8b9e6442a02a 3069 mibGet->Param.Class = LoRaMacDeviceClass;
Shaun Nelson 49:8b9e6442a02a 3070 break;
Shaun Nelson 49:8b9e6442a02a 3071 }
Shaun Nelson 49:8b9e6442a02a 3072 case MIB_NETWORK_JOINED: {
Shaun Nelson 49:8b9e6442a02a 3073 mibGet->Param.IsNetworkJoined = IsLoRaMacNetworkJoined;
Shaun Nelson 49:8b9e6442a02a 3074 break;
Shaun Nelson 49:8b9e6442a02a 3075 }
Shaun Nelson 49:8b9e6442a02a 3076 case MIB_ADR: {
Shaun Nelson 49:8b9e6442a02a 3077 mibGet->Param.AdrEnable = AdrCtrlOn;
Shaun Nelson 49:8b9e6442a02a 3078 break;
Shaun Nelson 49:8b9e6442a02a 3079 }
Shaun Nelson 49:8b9e6442a02a 3080 case MIB_NET_ID: {
Shaun Nelson 49:8b9e6442a02a 3081 mibGet->Param.NetID = LoRaMacNetID;
Shaun Nelson 49:8b9e6442a02a 3082 break;
Shaun Nelson 49:8b9e6442a02a 3083 }
Shaun Nelson 49:8b9e6442a02a 3084 case MIB_DEV_ADDR: {
Shaun Nelson 49:8b9e6442a02a 3085 mibGet->Param.DevAddr = LoRaMacDevAddr;
Shaun Nelson 49:8b9e6442a02a 3086 break;
Shaun Nelson 49:8b9e6442a02a 3087 }
Shaun Nelson 49:8b9e6442a02a 3088 case MIB_NWK_SKEY: {
Shaun Nelson 49:8b9e6442a02a 3089 mibGet->Param.NwkSKey = LoRaMacNwkSKey;
Shaun Nelson 49:8b9e6442a02a 3090 break;
Shaun Nelson 49:8b9e6442a02a 3091 }
Shaun Nelson 49:8b9e6442a02a 3092 case MIB_APP_SKEY: {
Shaun Nelson 49:8b9e6442a02a 3093 mibGet->Param.AppSKey = LoRaMacAppSKey;
Shaun Nelson 49:8b9e6442a02a 3094 break;
Shaun Nelson 49:8b9e6442a02a 3095 }
Shaun Nelson 49:8b9e6442a02a 3096 case MIB_PUBLIC_NETWORK: {
Shaun Nelson 49:8b9e6442a02a 3097 mibGet->Param.EnablePublicNetwork = PublicNetwork;
Shaun Nelson 49:8b9e6442a02a 3098 break;
Shaun Nelson 49:8b9e6442a02a 3099 }
Shaun Nelson 49:8b9e6442a02a 3100 case MIB_REPEATER_SUPPORT: {
Shaun Nelson 49:8b9e6442a02a 3101 mibGet->Param.EnableRepeaterSupport = RepeaterSupport;
Shaun Nelson 49:8b9e6442a02a 3102 break;
Shaun Nelson 49:8b9e6442a02a 3103 }
Shaun Nelson 49:8b9e6442a02a 3104 case MIB_CHANNELS: {
Shaun Nelson 49:8b9e6442a02a 3105 mibGet->Param.ChannelList = Channels;
Shaun Nelson 49:8b9e6442a02a 3106 break;
Shaun Nelson 49:8b9e6442a02a 3107 }
Shaun Nelson 49:8b9e6442a02a 3108 case MIB_RX2_CHANNEL: {
Shaun Nelson 49:8b9e6442a02a 3109 mibGet->Param.Rx2Channel = Rx2Channel;
Shaun Nelson 49:8b9e6442a02a 3110 break;
Shaun Nelson 49:8b9e6442a02a 3111 }
Shaun Nelson 49:8b9e6442a02a 3112 case MIB_CHANNELS_MASK: {
Shaun Nelson 49:8b9e6442a02a 3113 mibGet->Param.ChannelsMask = ChannelsMask;
Shaun Nelson 49:8b9e6442a02a 3114 break;
Shaun Nelson 49:8b9e6442a02a 3115 }
Shaun Nelson 49:8b9e6442a02a 3116 case MIB_CHANNELS_NB_REP: {
Shaun Nelson 49:8b9e6442a02a 3117 mibGet->Param.ChannelNbRep = ChannelsNbRep;
Shaun Nelson 49:8b9e6442a02a 3118 break;
Shaun Nelson 49:8b9e6442a02a 3119 }
Shaun Nelson 49:8b9e6442a02a 3120 case MIB_MAX_RX_WINDOW_DURATION: {
Shaun Nelson 49:8b9e6442a02a 3121 mibGet->Param.MaxRxWindow = MaxRxWindow;
Shaun Nelson 49:8b9e6442a02a 3122 break;
Shaun Nelson 49:8b9e6442a02a 3123 }
Shaun Nelson 49:8b9e6442a02a 3124 case MIB_RECEIVE_DELAY_1: {
Shaun Nelson 49:8b9e6442a02a 3125 mibGet->Param.ReceiveDelay1 = ReceiveDelay1;
Shaun Nelson 49:8b9e6442a02a 3126 break;
Shaun Nelson 49:8b9e6442a02a 3127 }
Shaun Nelson 49:8b9e6442a02a 3128 case MIB_RECEIVE_DELAY_2: {
Shaun Nelson 49:8b9e6442a02a 3129 mibGet->Param.ReceiveDelay2 = ReceiveDelay2;
Shaun Nelson 49:8b9e6442a02a 3130 break;
Shaun Nelson 49:8b9e6442a02a 3131 }
Shaun Nelson 49:8b9e6442a02a 3132 case MIB_JOIN_ACCEPT_DELAY_1: {
Shaun Nelson 49:8b9e6442a02a 3133 mibGet->Param.JoinAcceptDelay1 = JoinAcceptDelay1;
Shaun Nelson 49:8b9e6442a02a 3134 break;
Shaun Nelson 49:8b9e6442a02a 3135 }
Shaun Nelson 49:8b9e6442a02a 3136 case MIB_JOIN_ACCEPT_DELAY_2: {
Shaun Nelson 49:8b9e6442a02a 3137 mibGet->Param.JoinAcceptDelay2 = JoinAcceptDelay2;
Shaun Nelson 49:8b9e6442a02a 3138 break;
Shaun Nelson 49:8b9e6442a02a 3139 }
Shaun Nelson 49:8b9e6442a02a 3140 case MIB_CHANNELS_DEFAULT_DATARATE: {
Shaun Nelson 49:8b9e6442a02a 3141 mibGet->Param.ChannelsDefaultDatarate = ChannelsDefaultDatarate;
Shaun Nelson 49:8b9e6442a02a 3142 break;
Shaun Nelson 49:8b9e6442a02a 3143 }
Shaun Nelson 49:8b9e6442a02a 3144 case MIB_CHANNELS_DATARATE: {
Shaun Nelson 49:8b9e6442a02a 3145 mibGet->Param.ChannelsDatarate = ChannelsDatarate;
Shaun Nelson 49:8b9e6442a02a 3146 break;
Shaun Nelson 49:8b9e6442a02a 3147 }
Shaun Nelson 49:8b9e6442a02a 3148 case MIB_CHANNELS_TX_POWER: {
Shaun Nelson 49:8b9e6442a02a 3149 mibGet->Param.ChannelsTxPower = ChannelsTxPower;
Shaun Nelson 49:8b9e6442a02a 3150 break;
Shaun Nelson 49:8b9e6442a02a 3151 }
Shaun Nelson 49:8b9e6442a02a 3152 case MIB_UPLINK_COUNTER: {
Shaun Nelson 49:8b9e6442a02a 3153 mibGet->Param.UpLinkCounter = UpLinkCounter;
Shaun Nelson 49:8b9e6442a02a 3154 break;
Shaun Nelson 49:8b9e6442a02a 3155 }
Shaun Nelson 49:8b9e6442a02a 3156 case MIB_DOWNLINK_COUNTER: {
Shaun Nelson 49:8b9e6442a02a 3157 mibGet->Param.DownLinkCounter = DownLinkCounter;
Shaun Nelson 49:8b9e6442a02a 3158 break;
Shaun Nelson 49:8b9e6442a02a 3159 }
Shaun Nelson 49:8b9e6442a02a 3160 case MIB_MULTICAST_CHANNEL: {
Shaun Nelson 49:8b9e6442a02a 3161 mibGet->Param.MulticastList = MulticastChannels;
Shaun Nelson 49:8b9e6442a02a 3162 break;
Shaun Nelson 49:8b9e6442a02a 3163 }
Shaun Nelson 49:8b9e6442a02a 3164 default:
Shaun Nelson 49:8b9e6442a02a 3165 status = LORAMAC_STATUS_SERVICE_UNKNOWN;
Shaun Nelson 49:8b9e6442a02a 3166 break;
Shaun Nelson 49:8b9e6442a02a 3167 }
Shaun Nelson 49:8b9e6442a02a 3168
Shaun Nelson 49:8b9e6442a02a 3169 return status;
Shaun Nelson 49:8b9e6442a02a 3170 }
Shaun Nelson 49:8b9e6442a02a 3171
Shaun Nelson 49:8b9e6442a02a 3172 LoRaMacStatus_t LoRaMacMibSetRequestConfirm(MibRequestConfirm_t* mibSet) {
Shaun Nelson 49:8b9e6442a02a 3173 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 3174
Shaun Nelson 49:8b9e6442a02a 3175 if (mibSet == NULL) {
Shaun Nelson 49:8b9e6442a02a 3176 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3177 }
Shaun Nelson 49:8b9e6442a02a 3178 if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) {
Shaun Nelson 49:8b9e6442a02a 3179 return LORAMAC_STATUS_BUSY;
Shaun Nelson 49:8b9e6442a02a 3180 }
Shaun Nelson 49:8b9e6442a02a 3181
Shaun Nelson 49:8b9e6442a02a 3182 switch (mibSet->Type) {
Shaun Nelson 49:8b9e6442a02a 3183 case MIB_DEVICE_CLASS: {
Shaun Nelson 49:8b9e6442a02a 3184 LoRaMacDeviceClass = mibSet->Param.Class;
Shaun Nelson 49:8b9e6442a02a 3185 switch (LoRaMacDeviceClass) {
Shaun Nelson 49:8b9e6442a02a 3186 case CLASS_A: {
Shaun Nelson 49:8b9e6442a02a 3187 // Set the radio into sleep to setup a defined state
Shaun Nelson 49:8b9e6442a02a 3188 Radio.Sleep();
Shaun Nelson 49:8b9e6442a02a 3189 break;
mluis 2:14a5d6ad92d5 3190 }
Shaun Nelson 49:8b9e6442a02a 3191 case CLASS_B: {
Shaun Nelson 49:8b9e6442a02a 3192 break;
mluis 4:37c12dbc8dc7 3193 }
Shaun Nelson 49:8b9e6442a02a 3194 case CLASS_C: {
Shaun Nelson 49:8b9e6442a02a 3195 // Set the NodeAckRequested indicator to default
Shaun Nelson 49:8b9e6442a02a 3196 NodeAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 3197 OnRxWindow2TimerEvent();
Shaun Nelson 49:8b9e6442a02a 3198 break;
mluis 2:14a5d6ad92d5 3199 }
Shaun Nelson 49:8b9e6442a02a 3200 }
Shaun Nelson 49:8b9e6442a02a 3201 break;
Shaun Nelson 49:8b9e6442a02a 3202 }
Shaun Nelson 49:8b9e6442a02a 3203 case MIB_NETWORK_JOINED: {
Shaun Nelson 49:8b9e6442a02a 3204 IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined;
Shaun Nelson 49:8b9e6442a02a 3205 #if defined(USE_BAND_915)
Shaun Nelson 49:8b9e6442a02a 3206 if (IsLoRaMacNetworkJoined == false) {
Shaun Nelson 49:8b9e6442a02a 3207 NextJoinBlock = 0;
Shaun Nelson 49:8b9e6442a02a 3208 JoinBlocksRemaining = 0xff;
Shaun Nelson 49:8b9e6442a02a 3209 Join500KHzRemaining = 0xff;
Shaun Nelson 49:8b9e6442a02a 3210 }
snelson 9:ad93de20d720 3211 #endif
Shaun Nelson 49:8b9e6442a02a 3212 break;
Shaun Nelson 49:8b9e6442a02a 3213 }
Shaun Nelson 49:8b9e6442a02a 3214 case MIB_ADR: {
Shaun Nelson 49:8b9e6442a02a 3215 AdrCtrlOn = mibSet->Param.AdrEnable;
Shaun Nelson 49:8b9e6442a02a 3216 break;
Shaun Nelson 49:8b9e6442a02a 3217 }
Shaun Nelson 49:8b9e6442a02a 3218 case MIB_NET_ID: {
Shaun Nelson 49:8b9e6442a02a 3219 LoRaMacNetID = mibSet->Param.NetID;
Shaun Nelson 49:8b9e6442a02a 3220 break;
Shaun Nelson 49:8b9e6442a02a 3221 }
Shaun Nelson 49:8b9e6442a02a 3222 case MIB_DEV_ADDR: {
Shaun Nelson 49:8b9e6442a02a 3223 LoRaMacDevAddr = mibSet->Param.DevAddr;
Shaun Nelson 49:8b9e6442a02a 3224 break;
Shaun Nelson 49:8b9e6442a02a 3225 }
Shaun Nelson 49:8b9e6442a02a 3226 case MIB_NWK_SKEY: {
Shaun Nelson 49:8b9e6442a02a 3227 if (mibSet->Param.NwkSKey != NULL) {
Shaun Nelson 49:8b9e6442a02a 3228 memcpy1(LoRaMacNwkSKey, mibSet->Param.NwkSKey, sizeof(LoRaMacNwkSKey));
Shaun Nelson 49:8b9e6442a02a 3229 }
Shaun Nelson 49:8b9e6442a02a 3230 else {
Shaun Nelson 49:8b9e6442a02a 3231 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3232 }
Shaun Nelson 49:8b9e6442a02a 3233 break;
Shaun Nelson 49:8b9e6442a02a 3234 }
Shaun Nelson 49:8b9e6442a02a 3235 case MIB_APP_SKEY: {
Shaun Nelson 49:8b9e6442a02a 3236 if (mibSet->Param.AppSKey != NULL) {
Shaun Nelson 49:8b9e6442a02a 3237 memcpy1(LoRaMacAppSKey, mibSet->Param.AppSKey, sizeof(LoRaMacAppSKey));
Shaun Nelson 49:8b9e6442a02a 3238 }
Shaun Nelson 49:8b9e6442a02a 3239 else {
Shaun Nelson 49:8b9e6442a02a 3240 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3241 }
Shaun Nelson 49:8b9e6442a02a 3242 break;
Shaun Nelson 49:8b9e6442a02a 3243 }
Shaun Nelson 49:8b9e6442a02a 3244 case MIB_PUBLIC_NETWORK: {
Shaun Nelson 49:8b9e6442a02a 3245 SetPublicNetwork(mibSet->Param.EnablePublicNetwork);
Shaun Nelson 49:8b9e6442a02a 3246 break;
Shaun Nelson 49:8b9e6442a02a 3247 }
Shaun Nelson 49:8b9e6442a02a 3248 case MIB_REPEATER_SUPPORT: {
Shaun Nelson 49:8b9e6442a02a 3249 RepeaterSupport = mibSet->Param.EnableRepeaterSupport;
Shaun Nelson 49:8b9e6442a02a 3250 break;
Shaun Nelson 49:8b9e6442a02a 3251 }
Shaun Nelson 49:8b9e6442a02a 3252 case MIB_RX2_CHANNEL: {
Shaun Nelson 49:8b9e6442a02a 3253 Rx2Channel = mibSet->Param.Rx2Channel;
Shaun Nelson 49:8b9e6442a02a 3254 break;
Shaun Nelson 49:8b9e6442a02a 3255 }
Shaun Nelson 49:8b9e6442a02a 3256 case MIB_CHANNELS_MASK: {
Shaun Nelson 49:8b9e6442a02a 3257 if (mibSet->Param.ChannelsMask) {
Shaun Nelson 49:8b9e6442a02a 3258 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 3259 bool chanMaskState = true;
Shaun Nelson 49:8b9e6442a02a 3260
Shaun Nelson 49:8b9e6442a02a 3261 #if defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 3262 chanMaskState = ValidateChannelMask(mibSet->Param.ChannelsMask);
Shaun Nelson 49:8b9e6442a02a 3263 #endif
Shaun Nelson 49:8b9e6442a02a 3264 if (chanMaskState == true) {
Shaun Nelson 49:8b9e6442a02a 3265 if ((CountNbEnabled125kHzChannels(mibSet->Param.ChannelsMask) < HYBRD_CHNLS_MIN) &&
Shaun Nelson 49:8b9e6442a02a 3266 (CountNbEnabled125kHzChannels(mibSet->Param.ChannelsMask) > 0)) {
Shaun Nelson 49:8b9e6442a02a 3267 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3268 }
Shaun Nelson 49:8b9e6442a02a 3269 else {
Shaun Nelson 49:8b9e6442a02a 3270 memcpy1((uint8_t*)ChannelsMask, (uint8_t*)mibSet->Param.ChannelsMask,
Shaun Nelson 49:8b9e6442a02a 3271 sizeof(ChannelsMask));
Shaun Nelson 49:8b9e6442a02a 3272 for (uint8_t i = 0; i < sizeof(ChannelsMask) / 2; i++) {
Shaun Nelson 49:8b9e6442a02a 3273 // Disable channels which are no longer available
Shaun Nelson 49:8b9e6442a02a 3274 ChannelsMaskRemaining[i] &= ChannelsMask[i];
mluis 2:14a5d6ad92d5 3275 }
Shaun Nelson 49:8b9e6442a02a 3276 }
mluis 2:14a5d6ad92d5 3277 }
Shaun Nelson 49:8b9e6442a02a 3278 else {
Shaun Nelson 49:8b9e6442a02a 3279 status = LORAMAC_STATUS_PARAMETER_INVALID;
mluis 4:37c12dbc8dc7 3280 }
Shaun Nelson 49:8b9e6442a02a 3281 #else
Shaun Nelson 49:8b9e6442a02a 3282 memcpy1((uint8_t*)ChannelsMask, (uint8_t*)mibSet->Param.ChannelsMask, 2);
Shaun Nelson 49:8b9e6442a02a 3283 #endif
Shaun Nelson 49:8b9e6442a02a 3284 }
Shaun Nelson 49:8b9e6442a02a 3285 else {
Shaun Nelson 49:8b9e6442a02a 3286 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3287 }
Shaun Nelson 49:8b9e6442a02a 3288 break;
Shaun Nelson 49:8b9e6442a02a 3289 }
Shaun Nelson 49:8b9e6442a02a 3290 case MIB_CHANNELS_NB_REP: {
Shaun Nelson 49:8b9e6442a02a 3291 if ((mibSet->Param.ChannelNbRep >= 1) && (mibSet->Param.ChannelNbRep <= 15)) {
Shaun Nelson 49:8b9e6442a02a 3292 ChannelsNbRep = mibSet->Param.ChannelNbRep;
Shaun Nelson 49:8b9e6442a02a 3293 }
Shaun Nelson 49:8b9e6442a02a 3294 else {
Shaun Nelson 49:8b9e6442a02a 3295 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3296 }
Shaun Nelson 49:8b9e6442a02a 3297 break;
Shaun Nelson 49:8b9e6442a02a 3298 }
Shaun Nelson 49:8b9e6442a02a 3299 case MIB_MAX_RX_WINDOW_DURATION: {
Shaun Nelson 49:8b9e6442a02a 3300 MaxRxWindow = mibSet->Param.MaxRxWindow;
Shaun Nelson 49:8b9e6442a02a 3301 break;
Shaun Nelson 49:8b9e6442a02a 3302 }
Shaun Nelson 49:8b9e6442a02a 3303 case MIB_RECEIVE_DELAY_1: {
Shaun Nelson 49:8b9e6442a02a 3304 ReceiveDelay1 = mibSet->Param.ReceiveDelay1;
Shaun Nelson 49:8b9e6442a02a 3305 break;
Shaun Nelson 49:8b9e6442a02a 3306 }
Shaun Nelson 49:8b9e6442a02a 3307 case MIB_RECEIVE_DELAY_2: {
Shaun Nelson 49:8b9e6442a02a 3308 ReceiveDelay2 = mibSet->Param.ReceiveDelay2;
Shaun Nelson 49:8b9e6442a02a 3309 break;
Shaun Nelson 49:8b9e6442a02a 3310 }
Shaun Nelson 49:8b9e6442a02a 3311 case MIB_JOIN_ACCEPT_DELAY_1: {
Shaun Nelson 49:8b9e6442a02a 3312 JoinAcceptDelay1 = mibSet->Param.JoinAcceptDelay1;
Shaun Nelson 49:8b9e6442a02a 3313 break;
Shaun Nelson 49:8b9e6442a02a 3314 }
Shaun Nelson 49:8b9e6442a02a 3315 case MIB_JOIN_ACCEPT_DELAY_2: {
Shaun Nelson 49:8b9e6442a02a 3316 JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2;
Shaun Nelson 49:8b9e6442a02a 3317 break;
mluis 0:91d1a7783bb9 3318 }
Shaun Nelson 49:8b9e6442a02a 3319 case MIB_CHANNELS_DEFAULT_DATARATE: {
Shaun Nelson 49:8b9e6442a02a 3320 if (ValueInRange(mibSet->Param.ChannelsDefaultDatarate, LORAMAC_TX_MIN_DATARATE,
Shaun Nelson 49:8b9e6442a02a 3321 LORAMAC_TX_MAX_DATARATE)) {
Shaun Nelson 49:8b9e6442a02a 3322 ChannelsDefaultDatarate = mibSet->Param.ChannelsDefaultDatarate;
Shaun Nelson 49:8b9e6442a02a 3323 }
Shaun Nelson 49:8b9e6442a02a 3324 else {
Shaun Nelson 49:8b9e6442a02a 3325 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3326 }
Shaun Nelson 49:8b9e6442a02a 3327 break;
Shaun Nelson 49:8b9e6442a02a 3328 }
Shaun Nelson 49:8b9e6442a02a 3329 case MIB_CHANNELS_DATARATE: {
Shaun Nelson 49:8b9e6442a02a 3330 if (ValueInRange(mibSet->Param.ChannelsDatarate, LORAMAC_TX_MIN_DATARATE,
Shaun Nelson 49:8b9e6442a02a 3331 LORAMAC_TX_MAX_DATARATE)) {
Shaun Nelson 49:8b9e6442a02a 3332 ChannelsDatarate = mibSet->Param.ChannelsDatarate;
Shaun Nelson 49:8b9e6442a02a 3333 }
Shaun Nelson 49:8b9e6442a02a 3334 else {
Shaun Nelson 49:8b9e6442a02a 3335 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3336 }
Shaun Nelson 49:8b9e6442a02a 3337 break;
Shaun Nelson 49:8b9e6442a02a 3338 }
Shaun Nelson 49:8b9e6442a02a 3339 case MIB_CHANNELS_TX_POWER: {
Shaun Nelson 49:8b9e6442a02a 3340 if (ValueInRange(mibSet->Param.ChannelsTxPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER)) {
Shaun Nelson 49:8b9e6442a02a 3341 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 3342 int8_t txPower = LimitTxPower(mibSet->Param.ChannelsTxPower);
Shaun Nelson 49:8b9e6442a02a 3343 if (txPower == mibSet->Param.ChannelsTxPower) {
Shaun Nelson 49:8b9e6442a02a 3344 ChannelsTxPower = mibSet->Param.ChannelsTxPower;
Shaun Nelson 49:8b9e6442a02a 3345 }
Shaun Nelson 49:8b9e6442a02a 3346 else {
Shaun Nelson 49:8b9e6442a02a 3347 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3348 }
mluis 3:b9d87593a8ae 3349 #else
Shaun Nelson 49:8b9e6442a02a 3350 ChannelsTxPower = mibSet->Param.ChannelsTxPower;
Shaun Nelson 49:8b9e6442a02a 3351 #endif
Shaun Nelson 49:8b9e6442a02a 3352 }
Shaun Nelson 49:8b9e6442a02a 3353 else {
Shaun Nelson 49:8b9e6442a02a 3354 status = LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3355 }
Shaun Nelson 49:8b9e6442a02a 3356 break;
mluis 0:91d1a7783bb9 3357 }
Shaun Nelson 49:8b9e6442a02a 3358 case MIB_UPLINK_COUNTER: {
Shaun Nelson 49:8b9e6442a02a 3359 UpLinkCounter = mibSet->Param.UpLinkCounter;
Shaun Nelson 49:8b9e6442a02a 3360 break;
Shaun Nelson 49:8b9e6442a02a 3361 }
Shaun Nelson 49:8b9e6442a02a 3362 case MIB_DOWNLINK_COUNTER: {
Shaun Nelson 49:8b9e6442a02a 3363 DownLinkCounter = mibSet->Param.DownLinkCounter;
Shaun Nelson 49:8b9e6442a02a 3364 break;
mluis 0:91d1a7783bb9 3365 }
Shaun Nelson 49:8b9e6442a02a 3366 default:
Shaun Nelson 49:8b9e6442a02a 3367 status = LORAMAC_STATUS_SERVICE_UNKNOWN;
Shaun Nelson 49:8b9e6442a02a 3368 break;
Shaun Nelson 49:8b9e6442a02a 3369 }
Shaun Nelson 49:8b9e6442a02a 3370
Shaun Nelson 49:8b9e6442a02a 3371 return status;
Shaun Nelson 49:8b9e6442a02a 3372 }
Shaun Nelson 49:8b9e6442a02a 3373
Shaun Nelson 49:8b9e6442a02a 3374 LoRaMacStatus_t LoRaMacChannelAdd(uint8_t id, ChannelParams_t params) {
Shaun Nelson 49:8b9e6442a02a 3375 #if (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
Shaun Nelson 49:8b9e6442a02a 3376 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3377 #else
Shaun Nelson 49:8b9e6442a02a 3378 bool datarateInvalid = false;
Shaun Nelson 49:8b9e6442a02a 3379 bool frequencyInvalid = false;
Shaun Nelson 49:8b9e6442a02a 3380 uint8_t band = 0;
Shaun Nelson 49:8b9e6442a02a 3381
Shaun Nelson 49:8b9e6442a02a 3382 // The id must not exceed LORA_MAX_NB_CHANNELS
Shaun Nelson 49:8b9e6442a02a 3383 if (id >= LORA_MAX_NB_CHANNELS) {
Shaun Nelson 49:8b9e6442a02a 3384 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3385 }
Shaun Nelson 49:8b9e6442a02a 3386 // Validate if the MAC is in a correct state
Shaun Nelson 49:8b9e6442a02a 3387 if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) {
Shaun Nelson 49:8b9e6442a02a 3388 if ((LoRaMacState & MAC_TX_CONFIG) != MAC_TX_CONFIG) {
Shaun Nelson 49:8b9e6442a02a 3389 return LORAMAC_STATUS_BUSY;
mluis 0:91d1a7783bb9 3390 }
Shaun Nelson 49:8b9e6442a02a 3391 }
Shaun Nelson 49:8b9e6442a02a 3392 // Validate the datarate
Shaun Nelson 49:8b9e6442a02a 3393 if ((params.DrRange.Fields.Min > params.DrRange.Fields.Max) ||
Shaun Nelson 49:8b9e6442a02a 3394 (ValueInRange(params.DrRange.Fields.Min, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE) ==
Shaun Nelson 49:8b9e6442a02a 3395 false) ||
Shaun Nelson 49:8b9e6442a02a 3396 (ValueInRange(params.DrRange.Fields.Max, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE) ==
Shaun Nelson 49:8b9e6442a02a 3397 false)) {
Shaun Nelson 49:8b9e6442a02a 3398 datarateInvalid = true;
Shaun Nelson 49:8b9e6442a02a 3399 }
Shaun Nelson 49:8b9e6442a02a 3400
Shaun Nelson 49:8b9e6442a02a 3401 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 3402 if (id < 3) {
Shaun Nelson 49:8b9e6442a02a 3403 if (params.Frequency != Channels[id].Frequency) {
Shaun Nelson 49:8b9e6442a02a 3404 frequencyInvalid = true;
Shaun Nelson 49:8b9e6442a02a 3405 }
Shaun Nelson 49:8b9e6442a02a 3406
Shaun Nelson 49:8b9e6442a02a 3407 if (params.DrRange.Fields.Min > ChannelsDefaultDatarate) {
Shaun Nelson 49:8b9e6442a02a 3408 datarateInvalid = true;
Shaun Nelson 49:8b9e6442a02a 3409 }
Shaun Nelson 49:8b9e6442a02a 3410 if (ValueInRange(params.DrRange.Fields.Max, DR_5, LORAMAC_TX_MAX_DATARATE) == false) {
Shaun Nelson 49:8b9e6442a02a 3411 datarateInvalid = true;
Shaun Nelson 49:8b9e6442a02a 3412 }
Shaun Nelson 49:8b9e6442a02a 3413 }
Shaun Nelson 49:8b9e6442a02a 3414 #endif
Shaun Nelson 49:8b9e6442a02a 3415
Shaun Nelson 49:8b9e6442a02a 3416 // Validate the frequency
Shaun Nelson 49:8b9e6442a02a 3417 if ((Radio.CheckRfFrequency(params.Frequency) == true) && (params.Frequency > 0) &&
Shaun Nelson 49:8b9e6442a02a 3418 (frequencyInvalid == false)) {
Shaun Nelson 49:8b9e6442a02a 3419 #if defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 3420 if ((params.Frequency >= 865000000) && (params.Frequency <= 868000000)) {
Shaun Nelson 49:8b9e6442a02a 3421 band = BAND_G1_0;
Shaun Nelson 49:8b9e6442a02a 3422 }
Shaun Nelson 49:8b9e6442a02a 3423 else if ((params.Frequency > 868000000) && (params.Frequency <= 868600000)) {
Shaun Nelson 49:8b9e6442a02a 3424 band = BAND_G1_1;
Shaun Nelson 49:8b9e6442a02a 3425 }
Shaun Nelson 49:8b9e6442a02a 3426 else if ((params.Frequency >= 868700000) && (params.Frequency <= 869200000)) {
Shaun Nelson 49:8b9e6442a02a 3427 band = BAND_G1_2;
Shaun Nelson 49:8b9e6442a02a 3428 }
Shaun Nelson 49:8b9e6442a02a 3429 else if ((params.Frequency >= 869400000) && (params.Frequency <= 869650000)) {
Shaun Nelson 49:8b9e6442a02a 3430 band = BAND_G1_3;
Shaun Nelson 49:8b9e6442a02a 3431 }
Shaun Nelson 49:8b9e6442a02a 3432 else if ((params.Frequency >= 869700000) && (params.Frequency <= 870000000)) {
Shaun Nelson 49:8b9e6442a02a 3433 band = BAND_G1_4;
Shaun Nelson 49:8b9e6442a02a 3434 }
Shaun Nelson 49:8b9e6442a02a 3435 else {
Shaun Nelson 49:8b9e6442a02a 3436 frequencyInvalid = true;
mluis 0:91d1a7783bb9 3437 }
mluis 3:b9d87593a8ae 3438 #endif
Shaun Nelson 49:8b9e6442a02a 3439 }
Shaun Nelson 49:8b9e6442a02a 3440 else {
Shaun Nelson 49:8b9e6442a02a 3441 frequencyInvalid = true;
Shaun Nelson 49:8b9e6442a02a 3442 }
Shaun Nelson 49:8b9e6442a02a 3443
Shaun Nelson 49:8b9e6442a02a 3444 if ((datarateInvalid == true) && (frequencyInvalid == true)) {
Shaun Nelson 49:8b9e6442a02a 3445 return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
Shaun Nelson 49:8b9e6442a02a 3446 }
Shaun Nelson 49:8b9e6442a02a 3447 if (datarateInvalid == true) {
Shaun Nelson 49:8b9e6442a02a 3448 return LORAMAC_STATUS_DATARATE_INVALID;
Shaun Nelson 49:8b9e6442a02a 3449 }
Shaun Nelson 49:8b9e6442a02a 3450 if (frequencyInvalid == true) {
Shaun Nelson 49:8b9e6442a02a 3451 return LORAMAC_STATUS_FREQUENCY_INVALID;
Shaun Nelson 49:8b9e6442a02a 3452 }
Shaun Nelson 49:8b9e6442a02a 3453
Shaun Nelson 49:8b9e6442a02a 3454 // Every parameter is valid, activate the channel
Shaun Nelson 49:8b9e6442a02a 3455 Channels[id] = params;
Shaun Nelson 49:8b9e6442a02a 3456 Channels[id].Band = band;
Shaun Nelson 49:8b9e6442a02a 3457 ChannelsMask[0] |= (1 << id);
Shaun Nelson 49:8b9e6442a02a 3458
Shaun Nelson 49:8b9e6442a02a 3459 return LORAMAC_STATUS_OK;
mluis 0:91d1a7783bb9 3460 #endif
mluis 0:91d1a7783bb9 3461 }
mluis 0:91d1a7783bb9 3462
Shaun Nelson 49:8b9e6442a02a 3463 LoRaMacStatus_t LoRaMacChannelRemove(uint8_t id) {
Shaun Nelson 49:8b9e6442a02a 3464 #if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868)
Shaun Nelson 49:8b9e6442a02a 3465 if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) {
Shaun Nelson 49:8b9e6442a02a 3466 if ((LoRaMacState & MAC_TX_CONFIG) != MAC_TX_CONFIG) {
Shaun Nelson 49:8b9e6442a02a 3467 return LORAMAC_STATUS_BUSY;
mluis 3:b9d87593a8ae 3468 }
Shaun Nelson 49:8b9e6442a02a 3469 }
Shaun Nelson 49:8b9e6442a02a 3470
Shaun Nelson 49:8b9e6442a02a 3471 if ((id < 3) || (id >= LORA_MAX_NB_CHANNELS)) {
Shaun Nelson 49:8b9e6442a02a 3472 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3473 }
Shaun Nelson 49:8b9e6442a02a 3474 else {
Shaun Nelson 49:8b9e6442a02a 3475 // Remove the channel from the list of channels
Shaun Nelson 49:8b9e6442a02a 3476 Channels[id] = (ChannelParams_t){0, {0}, 0};
Shaun Nelson 49:8b9e6442a02a 3477
Shaun Nelson 49:8b9e6442a02a 3478 // Disable the channel as it doesn't exist anymore
Shaun Nelson 49:8b9e6442a02a 3479 if (DisableChannelInMask(id, ChannelsMask) == false) {
Shaun Nelson 49:8b9e6442a02a 3480 return LORAMAC_STATUS_PARAMETER_INVALID;
mluis 0:91d1a7783bb9 3481 }
Shaun Nelson 49:8b9e6442a02a 3482 }
Shaun Nelson 49:8b9e6442a02a 3483 return LORAMAC_STATUS_OK;
Shaun Nelson 49:8b9e6442a02a 3484 #elif (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
Shaun Nelson 49:8b9e6442a02a 3485 return LORAMAC_STATUS_PARAMETER_INVALID;
mluis 2:14a5d6ad92d5 3486 #endif
mluis 2:14a5d6ad92d5 3487 }
mluis 2:14a5d6ad92d5 3488
Shaun Nelson 49:8b9e6442a02a 3489 LoRaMacStatus_t LoRaMacMulticastChannelLink(MulticastParams_t* channelParam) {
Shaun Nelson 49:8b9e6442a02a 3490 if (channelParam == NULL) {
Shaun Nelson 49:8b9e6442a02a 3491 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3492 }
Shaun Nelson 49:8b9e6442a02a 3493 if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) {
Shaun Nelson 49:8b9e6442a02a 3494 return LORAMAC_STATUS_BUSY;
Shaun Nelson 49:8b9e6442a02a 3495 }
Shaun Nelson 49:8b9e6442a02a 3496
Shaun Nelson 49:8b9e6442a02a 3497 // Reset downlink counter
Shaun Nelson 49:8b9e6442a02a 3498 channelParam->DownLinkCounter = 0;
Shaun Nelson 49:8b9e6442a02a 3499
Shaun Nelson 49:8b9e6442a02a 3500 if (MulticastChannels == NULL) {
Shaun Nelson 49:8b9e6442a02a 3501 // New node is the fist element
Shaun Nelson 49:8b9e6442a02a 3502 MulticastChannels = channelParam;
Shaun Nelson 49:8b9e6442a02a 3503 }
Shaun Nelson 49:8b9e6442a02a 3504 else {
Shaun Nelson 49:8b9e6442a02a 3505 MulticastParams_t* cur = MulticastChannels;
Shaun Nelson 49:8b9e6442a02a 3506
Shaun Nelson 49:8b9e6442a02a 3507 // Search the last node in the list
Shaun Nelson 49:8b9e6442a02a 3508 while (cur->Next != NULL) {
Shaun Nelson 49:8b9e6442a02a 3509 cur = cur->Next;
mluis 0:91d1a7783bb9 3510 }
Shaun Nelson 49:8b9e6442a02a 3511 // This function always finds the last node
Shaun Nelson 49:8b9e6442a02a 3512 cur->Next = channelParam;
Shaun Nelson 49:8b9e6442a02a 3513 }
Shaun Nelson 49:8b9e6442a02a 3514
Shaun Nelson 49:8b9e6442a02a 3515 return LORAMAC_STATUS_OK;
mluis 0:91d1a7783bb9 3516 }
mluis 0:91d1a7783bb9 3517
Shaun Nelson 49:8b9e6442a02a 3518 LoRaMacStatus_t LoRaMacMulticastChannelUnlink(MulticastParams_t* channelParam) {
Shaun Nelson 49:8b9e6442a02a 3519 if (channelParam == NULL) {
Shaun Nelson 49:8b9e6442a02a 3520 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3521 }
Shaun Nelson 49:8b9e6442a02a 3522 if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) {
Shaun Nelson 49:8b9e6442a02a 3523 return LORAMAC_STATUS_BUSY;
Shaun Nelson 49:8b9e6442a02a 3524 }
Shaun Nelson 49:8b9e6442a02a 3525
Shaun Nelson 49:8b9e6442a02a 3526 if (MulticastChannels != NULL) {
Shaun Nelson 49:8b9e6442a02a 3527 if (MulticastChannels == channelParam) {
Shaun Nelson 49:8b9e6442a02a 3528 // First element
Shaun Nelson 49:8b9e6442a02a 3529 MulticastChannels = channelParam->Next;
mluis 2:14a5d6ad92d5 3530 }
Shaun Nelson 49:8b9e6442a02a 3531 else {
Shaun Nelson 49:8b9e6442a02a 3532 MulticastParams_t* cur = MulticastChannels;
Shaun Nelson 49:8b9e6442a02a 3533
Shaun Nelson 49:8b9e6442a02a 3534 // Search the node in the list
Shaun Nelson 49:8b9e6442a02a 3535 while (cur->Next && cur->Next != channelParam) {
Shaun Nelson 49:8b9e6442a02a 3536 cur = cur->Next;
Shaun Nelson 49:8b9e6442a02a 3537 }
Shaun Nelson 49:8b9e6442a02a 3538 // If we found the node, remove it
Shaun Nelson 49:8b9e6442a02a 3539 if (cur->Next) {
Shaun Nelson 49:8b9e6442a02a 3540 cur->Next = channelParam->Next;
Shaun Nelson 49:8b9e6442a02a 3541 }
mluis 0:91d1a7783bb9 3542 }
Shaun Nelson 49:8b9e6442a02a 3543 channelParam->Next = NULL;
Shaun Nelson 49:8b9e6442a02a 3544 }
Shaun Nelson 49:8b9e6442a02a 3545
Shaun Nelson 49:8b9e6442a02a 3546 return LORAMAC_STATUS_OK;
mluis 0:91d1a7783bb9 3547 }
mluis 0:91d1a7783bb9 3548
Shaun Nelson 49:8b9e6442a02a 3549 LoRaMacStatus_t LoRaMacMlmeRequest(MlmeReq_t* mlmeRequest) {
Shaun Nelson 49:8b9e6442a02a 3550 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
Shaun Nelson 49:8b9e6442a02a 3551 LoRaMacHeader_t macHdr;
Shaun Nelson 49:8b9e6442a02a 3552
Shaun Nelson 49:8b9e6442a02a 3553 if (mlmeRequest == NULL) {
Shaun Nelson 49:8b9e6442a02a 3554 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3555 }
Shaun Nelson 49:8b9e6442a02a 3556 if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) {
Shaun Nelson 49:8b9e6442a02a 3557 return LORAMAC_STATUS_BUSY;
Shaun Nelson 49:8b9e6442a02a 3558 }
Shaun Nelson 49:8b9e6442a02a 3559
Shaun Nelson 49:8b9e6442a02a 3560 memset1((uint8_t*)&MlmeConfirm, 0, sizeof(MlmeConfirm));
Shaun Nelson 49:8b9e6442a02a 3561
Shaun Nelson 49:8b9e6442a02a 3562 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
Shaun Nelson 49:8b9e6442a02a 3563
Shaun Nelson 49:8b9e6442a02a 3564 switch (mlmeRequest->Type) {
Shaun Nelson 49:8b9e6442a02a 3565 case MLME_JOIN: {
Shaun Nelson 49:8b9e6442a02a 3566 if ((LoRaMacState & MAC_TX_DELAYED) == MAC_TX_DELAYED) {
Shaun Nelson 49:8b9e6442a02a 3567 return LORAMAC_STATUS_BUSY;
Shaun Nelson 49:8b9e6442a02a 3568 }
Shaun Nelson 49:8b9e6442a02a 3569
Shaun Nelson 49:8b9e6442a02a 3570 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
Shaun Nelson 49:8b9e6442a02a 3571
Shaun Nelson 49:8b9e6442a02a 3572 if ((mlmeRequest->Req.Join.DevEui == NULL) || (mlmeRequest->Req.Join.AppEui == NULL) ||
Shaun Nelson 49:8b9e6442a02a 3573 (mlmeRequest->Req.Join.AppKey == NULL)) {
mluis 2:14a5d6ad92d5 3574 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3575 }
Shaun Nelson 49:8b9e6442a02a 3576
Shaun Nelson 49:8b9e6442a02a 3577 LoRaMacFlags.Bits.MlmeReq = 1;
Shaun Nelson 49:8b9e6442a02a 3578
Shaun Nelson 49:8b9e6442a02a 3579 LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
Shaun Nelson 49:8b9e6442a02a 3580 LoRaMacAppEui = mlmeRequest->Req.Join.AppEui;
Shaun Nelson 49:8b9e6442a02a 3581 LoRaMacAppKey = mlmeRequest->Req.Join.AppKey;
Shaun Nelson 49:8b9e6442a02a 3582
Shaun Nelson 49:8b9e6442a02a 3583 // Disable join retransmission dutycycle as it does not currently
Shaun Nelson 49:8b9e6442a02a 3584 // handle device reset
shaunkrnelson 22:43aa9a123248 3585 #if 0
snelson 8:4816c8449bf2 3586 if( LoRaMacCalcJoinBackOff( ) != 0 )
snelson 8:4816c8449bf2 3587 {
snelson 8:4816c8449bf2 3588 return LORAMAC_STATUS_TX_DCYCLE_EXCEEDED;
snelson 8:4816c8449bf2 3589 }
shaunkrnelson 22:43aa9a123248 3590 #endif
snelson 8:4816c8449bf2 3591
Shaun Nelson 49:8b9e6442a02a 3592 macHdr.Value = 0;
Shaun Nelson 49:8b9e6442a02a 3593 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
Shaun Nelson 49:8b9e6442a02a 3594
Shaun Nelson 49:8b9e6442a02a 3595 #if defined(USE_BAND_915)
Shaun Nelson 49:8b9e6442a02a 3596 if (IsLoRaMacNetworkJoined == true) {
Shaun Nelson 49:8b9e6442a02a 3597 NextJoinBlock = 0;
Shaun Nelson 49:8b9e6442a02a 3598 JoinBlocksRemaining = 0xff;
Shaun Nelson 49:8b9e6442a02a 3599 Join500KHzRemaining = 0xff;
Shaun Nelson 49:8b9e6442a02a 3600 IsLoRaMacNetworkJoined = false;
Shaun Nelson 49:8b9e6442a02a 3601 }
snelson 8:4816c8449bf2 3602 #endif
mluis 2:14a5d6ad92d5 3603
Shaun Nelson 49:8b9e6442a02a 3604 #if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)
Shaun Nelson 49:8b9e6442a02a 3605 #if defined(USE_BAND_915)
Shaun Nelson 49:8b9e6442a02a 3606 // Re-enable 500 kHz default channels
Shaun Nelson 49:8b9e6442a02a 3607 ChannelsMask[4] = 0x00FF;
Shaun Nelson 49:8b9e6442a02a 3608 #else // defined( USE_BAND_915_HYBRID )
Shaun Nelson 49:8b9e6442a02a 3609 // Re-enable 500 kHz default channels
Shaun Nelson 49:8b9e6442a02a 3610 ChannelsMask[4] = 0x0001;
mluis 3:b9d87593a8ae 3611 #endif
mluis 3:b9d87593a8ae 3612
Shaun Nelson 49:8b9e6442a02a 3613 static uint8_t drSwitch = 0;
Shaun Nelson 49:8b9e6442a02a 3614
Shaun Nelson 49:8b9e6442a02a 3615 if ((++drSwitch & 0x01) == 0x01) {
Shaun Nelson 49:8b9e6442a02a 3616 ChannelsDatarate = DR_0;
Shaun Nelson 49:8b9e6442a02a 3617 }
Shaun Nelson 49:8b9e6442a02a 3618 else {
Shaun Nelson 49:8b9e6442a02a 3619 ChannelsDatarate = DR_4;
Shaun Nelson 49:8b9e6442a02a 3620 }
mluis 2:14a5d6ad92d5 3621 #endif
mluis 2:14a5d6ad92d5 3622
Shaun Nelson 49:8b9e6442a02a 3623 status = Send(&macHdr, 0, NULL, 0);
Shaun Nelson 49:8b9e6442a02a 3624 break;
mluis 2:14a5d6ad92d5 3625 }
Shaun Nelson 49:8b9e6442a02a 3626 case MLME_LINK_CHECK: {
Shaun Nelson 49:8b9e6442a02a 3627 LoRaMacFlags.Bits.MlmeReq = 1;
Shaun Nelson 49:8b9e6442a02a 3628 // LoRaMac will send this command piggy-pack
Shaun Nelson 49:8b9e6442a02a 3629 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
Shaun Nelson 49:8b9e6442a02a 3630
Shaun Nelson 49:8b9e6442a02a 3631 status = AddMacCommand(MOTE_MAC_LINK_CHECK_REQ, 0, 0);
Shaun Nelson 49:8b9e6442a02a 3632 break;
mluis 2:14a5d6ad92d5 3633 }
Shaun Nelson 49:8b9e6442a02a 3634 default:
Shaun Nelson 49:8b9e6442a02a 3635 break;
Shaun Nelson 49:8b9e6442a02a 3636 }
Shaun Nelson 49:8b9e6442a02a 3637
Shaun Nelson 49:8b9e6442a02a 3638 if (status != LORAMAC_STATUS_OK) {
Shaun Nelson 49:8b9e6442a02a 3639 NodeAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 3640 LoRaMacFlags.Bits.MlmeReq = 0;
Shaun Nelson 49:8b9e6442a02a 3641 }
Shaun Nelson 49:8b9e6442a02a 3642
Shaun Nelson 49:8b9e6442a02a 3643 return status;
mluis 0:91d1a7783bb9 3644 }
mluis 0:91d1a7783bb9 3645
Shaun Nelson 49:8b9e6442a02a 3646 LoRaMacStatus_t LoRaMacMcpsRequest(McpsReq_t* mcpsRequest) {
Shaun Nelson 49:8b9e6442a02a 3647 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
Shaun Nelson 49:8b9e6442a02a 3648 LoRaMacHeader_t macHdr;
Shaun Nelson 49:8b9e6442a02a 3649 uint8_t fPort = 0;
Shaun Nelson 49:8b9e6442a02a 3650 void* fBuffer;
Shaun Nelson 49:8b9e6442a02a 3651 uint16_t fBufferSize;
Shaun Nelson 49:8b9e6442a02a 3652 int8_t datarate;
Shaun Nelson 49:8b9e6442a02a 3653 bool readyToSend = false;
Shaun Nelson 49:8b9e6442a02a 3654
Shaun Nelson 49:8b9e6442a02a 3655 if (mcpsRequest == NULL) {
Shaun Nelson 49:8b9e6442a02a 3656 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3657 }
Shaun Nelson 49:8b9e6442a02a 3658 if (((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) ||
Shaun Nelson 49:8b9e6442a02a 3659 ((LoRaMacState & MAC_TX_DELAYED) == MAC_TX_DELAYED)) {
Shaun Nelson 49:8b9e6442a02a 3660 return LORAMAC_STATUS_BUSY;
Shaun Nelson 49:8b9e6442a02a 3661 }
Shaun Nelson 49:8b9e6442a02a 3662
Shaun Nelson 49:8b9e6442a02a 3663 macHdr.Value = 0;
Shaun Nelson 49:8b9e6442a02a 3664 memset1((uint8_t*)&McpsConfirm, 0, sizeof(McpsConfirm));
Shaun Nelson 49:8b9e6442a02a 3665 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
Shaun Nelson 49:8b9e6442a02a 3666
Shaun Nelson 49:8b9e6442a02a 3667 switch (mcpsRequest->Type) {
Shaun Nelson 49:8b9e6442a02a 3668 case MCPS_UNCONFIRMED: {
Shaun Nelson 49:8b9e6442a02a 3669 readyToSend = true;
Shaun Nelson 49:8b9e6442a02a 3670 AckTimeoutRetries = 1;
Shaun Nelson 49:8b9e6442a02a 3671 AckTimeoutRetriesCounter = 1;
Shaun Nelson 49:8b9e6442a02a 3672
Shaun Nelson 49:8b9e6442a02a 3673 macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
Shaun Nelson 49:8b9e6442a02a 3674 fPort = mcpsRequest->Req.Unconfirmed.fPort;
Shaun Nelson 49:8b9e6442a02a 3675 fBuffer = mcpsRequest->Req.Unconfirmed.fBuffer;
Shaun Nelson 49:8b9e6442a02a 3676 fBufferSize = mcpsRequest->Req.Unconfirmed.fBufferSize;
Shaun Nelson 49:8b9e6442a02a 3677 datarate = mcpsRequest->Req.Unconfirmed.Datarate;
Shaun Nelson 49:8b9e6442a02a 3678 break;
mluis 2:14a5d6ad92d5 3679 }
Shaun Nelson 49:8b9e6442a02a 3680 case MCPS_CONFIRMED: {
Shaun Nelson 49:8b9e6442a02a 3681 readyToSend = true;
Shaun Nelson 49:8b9e6442a02a 3682 AckTimeoutRetriesCounter = 1;
Shaun Nelson 49:8b9e6442a02a 3683 AckTimeoutRetries = mcpsRequest->Req.Confirmed.NbTrials;
Shaun Nelson 49:8b9e6442a02a 3684
Shaun Nelson 49:8b9e6442a02a 3685 macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
Shaun Nelson 49:8b9e6442a02a 3686 fPort = mcpsRequest->Req.Confirmed.fPort;
Shaun Nelson 49:8b9e6442a02a 3687 fBuffer = mcpsRequest->Req.Confirmed.fBuffer;
Shaun Nelson 49:8b9e6442a02a 3688 fBufferSize = mcpsRequest->Req.Confirmed.fBufferSize;
Shaun Nelson 49:8b9e6442a02a 3689 datarate = mcpsRequest->Req.Confirmed.Datarate;
Shaun Nelson 49:8b9e6442a02a 3690 break;
mluis 2:14a5d6ad92d5 3691 }
Shaun Nelson 49:8b9e6442a02a 3692 case MCPS_PROPRIETARY: {
Shaun Nelson 49:8b9e6442a02a 3693 readyToSend = true;
Shaun Nelson 49:8b9e6442a02a 3694 AckTimeoutRetries = 1;
Shaun Nelson 49:8b9e6442a02a 3695
Shaun Nelson 49:8b9e6442a02a 3696 macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
Shaun Nelson 49:8b9e6442a02a 3697 fBuffer = mcpsRequest->Req.Proprietary.fBuffer;
Shaun Nelson 49:8b9e6442a02a 3698 fBufferSize = mcpsRequest->Req.Proprietary.fBufferSize;
Shaun Nelson 49:8b9e6442a02a 3699 datarate = mcpsRequest->Req.Proprietary.Datarate;
Shaun Nelson 49:8b9e6442a02a 3700 break;
mluis 2:14a5d6ad92d5 3701 }
Shaun Nelson 49:8b9e6442a02a 3702 default:
Shaun Nelson 49:8b9e6442a02a 3703 break;
Shaun Nelson 49:8b9e6442a02a 3704 }
Shaun Nelson 49:8b9e6442a02a 3705
Shaun Nelson 49:8b9e6442a02a 3706 if (readyToSend == true) {
Shaun Nelson 49:8b9e6442a02a 3707 if (AdrCtrlOn == false) {
Shaun Nelson 49:8b9e6442a02a 3708 if (ValueInRange(datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE) == true) {
Shaun Nelson 49:8b9e6442a02a 3709 ChannelsDatarate = datarate;
Shaun Nelson 49:8b9e6442a02a 3710 }
Shaun Nelson 49:8b9e6442a02a 3711 else {
Shaun Nelson 49:8b9e6442a02a 3712 return LORAMAC_STATUS_PARAMETER_INVALID;
Shaun Nelson 49:8b9e6442a02a 3713 }
mluis 2:14a5d6ad92d5 3714 }
mluis 2:14a5d6ad92d5 3715
Shaun Nelson 49:8b9e6442a02a 3716 status = Send(&macHdr, fPort, fBuffer, fBufferSize);
Shaun Nelson 49:8b9e6442a02a 3717 if (status == LORAMAC_STATUS_OK) {
Shaun Nelson 49:8b9e6442a02a 3718 McpsConfirm.McpsRequest = mcpsRequest->Type;
Shaun Nelson 49:8b9e6442a02a 3719 LoRaMacFlags.Bits.McpsReq = 1;
Shaun Nelson 49:8b9e6442a02a 3720 }
Shaun Nelson 49:8b9e6442a02a 3721 else {
Shaun Nelson 49:8b9e6442a02a 3722 NodeAckRequested = false;
Shaun Nelson 49:8b9e6442a02a 3723 }
Shaun Nelson 49:8b9e6442a02a 3724 }
Shaun Nelson 49:8b9e6442a02a 3725
Shaun Nelson 49:8b9e6442a02a 3726 return status;
mluis 0:91d1a7783bb9 3727 }
mluis 0:91d1a7783bb9 3728
Shaun Nelson 49:8b9e6442a02a 3729 TimerTime_t LoRaMacCalcJoinBackOff() {
Shaun Nelson 49:8b9e6442a02a 3730 TimerTime_t timeOff = 0;
Shaun Nelson 49:8b9e6442a02a 3731 TimerTime_t uptime;
Shaun Nelson 49:8b9e6442a02a 3732 TimerTime_t currDCycleEndTime;
Shaun Nelson 49:8b9e6442a02a 3733 TimerTime_t prevDCycleEndTime;
Shaun Nelson 49:8b9e6442a02a 3734 TimerTime_t period;
Shaun Nelson 49:8b9e6442a02a 3735 TimerTime_t onAirTimeMax;
Shaun Nelson 49:8b9e6442a02a 3736 TimerTime_t lastJoinTime;
Shaun Nelson 49:8b9e6442a02a 3737 TimerTime_t elapsedTime;
Shaun Nelson 49:8b9e6442a02a 3738 uint8_t dcyclePeriod;
Shaun Nelson 49:8b9e6442a02a 3739
Shaun Nelson 49:8b9e6442a02a 3740 // Check retransmit duty-cycle is enabled
Shaun Nelson 49:8b9e6442a02a 3741 if (JOIN_NB_RETRANSMISSION_DCYCLES == 0)
Shaun Nelson 49:8b9e6442a02a 3742 return 0;
Shaun Nelson 49:8b9e6442a02a 3743
Shaun Nelson 49:8b9e6442a02a 3744 // Normalize system time values to seconds
Shaun Nelson 49:8b9e6442a02a 3745 uptime = TimerGetCurrentTime() / 1e6;
Shaun Nelson 49:8b9e6442a02a 3746 lastJoinTime = LastJoinTxTime / 1e6;
Shaun Nelson 49:8b9e6442a02a 3747
Shaun Nelson 49:8b9e6442a02a 3748 // Get dutycycle for current time
Shaun Nelson 49:8b9e6442a02a 3749 prevDCycleEndTime = 0;
Shaun Nelson 49:8b9e6442a02a 3750 currDCycleEndTime = 0;
Shaun Nelson 49:8b9e6442a02a 3751 for (dcyclePeriod = 0; dcyclePeriod < JOIN_NB_RETRANSMISSION_DCYCLES; dcyclePeriod++) {
Shaun Nelson 49:8b9e6442a02a 3752 prevDCycleEndTime = currDCycleEndTime;
Shaun Nelson 49:8b9e6442a02a 3753 currDCycleEndTime += JoinReTransmitDCycle[dcyclePeriod].period;
Shaun Nelson 49:8b9e6442a02a 3754
Shaun Nelson 49:8b9e6442a02a 3755 bool isCurrentPeriod = uptime < currDCycleEndTime;
Shaun Nelson 49:8b9e6442a02a 3756
Shaun Nelson 49:8b9e6442a02a 3757 if (isCurrentPeriod || (dcyclePeriod == (JOIN_NB_RETRANSMISSION_DCYCLES - 1))) {
Shaun Nelson 49:8b9e6442a02a 3758 period = JoinReTransmitDCycle[dcyclePeriod].period;
Shaun Nelson 49:8b9e6442a02a 3759 onAirTimeMax = JoinReTransmitDCycle[dcyclePeriod].onAirTimeMax;
Shaun Nelson 49:8b9e6442a02a 3760 if (isCurrentPeriod == true)
Shaun Nelson 49:8b9e6442a02a 3761 break;
snelson 8:4816c8449bf2 3762 }
Shaun Nelson 49:8b9e6442a02a 3763 }
Shaun Nelson 49:8b9e6442a02a 3764
Shaun Nelson 49:8b9e6442a02a 3765 // Clear aggregate on air time if dutycycle period of last join has elapsed
Shaun Nelson 49:8b9e6442a02a 3766 if (lastJoinTime < prevDCycleEndTime) {
Shaun Nelson 49:8b9e6442a02a 3767 JoinAggTimeOnAir = 0;
Shaun Nelson 49:8b9e6442a02a 3768 }
Shaun Nelson 49:8b9e6442a02a 3769 else {
Shaun Nelson 49:8b9e6442a02a 3770 elapsedTime = (uptime - prevDCycleEndTime) % period;
Shaun Nelson 49:8b9e6442a02a 3771
Shaun Nelson 49:8b9e6442a02a 3772 if (dcyclePeriod == JOIN_NB_RETRANSMISSION_DCYCLES) {
Shaun Nelson 49:8b9e6442a02a 3773 if (((uptime - prevDCycleEndTime) / period) > ((lastJoinTime - prevDCycleEndTime) / period)) {
snelson 8:4816c8449bf2 3774 JoinAggTimeOnAir = 0;
Shaun Nelson 49:8b9e6442a02a 3775 }
snelson 8:4816c8449bf2 3776 }
Shaun Nelson 49:8b9e6442a02a 3777 }
Shaun Nelson 49:8b9e6442a02a 3778
Shaun Nelson 49:8b9e6442a02a 3779 if (JoinAggTimeOnAir >= onAirTimeMax) {
Shaun Nelson 49:8b9e6442a02a 3780 // time off is remaining time until beginning of next period
Shaun Nelson 49:8b9e6442a02a 3781 timeOff = (period - elapsedTime);
Shaun Nelson 49:8b9e6442a02a 3782 }
Shaun Nelson 49:8b9e6442a02a 3783
Shaun Nelson 49:8b9e6442a02a 3784 if (timeOff > JOIN_RETRANSMISSION_DC_WAIT_MAX)
Shaun Nelson 49:8b9e6442a02a 3785 timeOff = JOIN_RETRANSMISSION_DC_WAIT_MAX;
Shaun Nelson 49:8b9e6442a02a 3786
Shaun Nelson 49:8b9e6442a02a 3787 return (timeOff * 1e6);
mluis 0:91d1a7783bb9 3788 }
mluis 0:91d1a7783bb9 3789
Shaun Nelson 49:8b9e6442a02a 3790 void LoRaMacTestRxWindowsOn(bool enable) {
Shaun Nelson 49:8b9e6442a02a 3791 IsRxWindowsEnabled = enable;
mluis 0:91d1a7783bb9 3792 }
mluis 2:14a5d6ad92d5 3793
Shaun Nelson 49:8b9e6442a02a 3794 void LoRaMacTestSetMic(uint16_t txPacketCounter) {
Shaun Nelson 49:8b9e6442a02a 3795 UpLinkCounter = txPacketCounter;
Shaun Nelson 49:8b9e6442a02a 3796 IsUpLinkCounterFixed = true;
mluis 2:14a5d6ad92d5 3797 }
Shaun Nelson 49:8b9e6442a02a 3798
Shaun Nelson 49:8b9e6442a02a 3799 void LoRaMacTestSetDutyCycleOn(bool enable) {
Shaun Nelson 49:8b9e6442a02a 3800 DutyCycleOn = enable;
Shaun Nelson 49:8b9e6442a02a 3801 }