end node on synchronous star LoRa network.

Dependencies:   SX127x sx12xx_hal TSL2561

radio chip selection

Radio chip driver is not included, allowing choice of radio device.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
if you're using SX1280, then import sx1280 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.

This project for use with LoRaWAN_singlechannel_gateway project.

Alternately gateway running on raspberry pi can be used as gateway.

LoRaWAN on single radio channel

Network description is at gateway project page. Synchronous star network.

Hardware Support

This project supports SX1276 and SX1272, sx126x kit, sx126x shield, and sx128x 2.4GHz. The ST board B-L072Z-LRWAN1 is also supported (TypeABZ module). When B-L072Z-LRWAN1 target is selected, TARGET_DISCO_L072CZ_LRWAN1 is defined by tools, allowing correct radio driver configuration for this platform. Alternately, any mbed board that can use LoRa radio shield board should work, but NUCLEO boards are tested.

End-node Unique ID

DevEUI is created from CPU serial number. AppEUI and AppKey are declared as software constants.

End-node Configuration

Data rate definition LORAMAC_DEFAULT_DATARATE configured in LoRaMac-definitions.h. See gateway project page for configuration of gateway.
LoRaWAN addressing is configured in Comissioning.h; only OTA mode is functional.
Header file board/lora_config.h, selects application layer options (i.e. sensors) to be compiled in.

Serial Interface

Serial port operates at 115200bps.
Application layer single_us915_main.cpp User button triggers uplink (i.e. blue button on nucleo board), or jumper enables continuously sends repeated uplink packets. The MAC layer holds each uplink request until the allocated timeslot.

commandargumentsdescription
?-print available commands
. (period)-print status (DevEUI, DevAddr, etc)
ullength integerset payload length of test uplink packets

sensor demo

Selected grove sensors may be plugged into SX1272 shield.
To enable, edit lora_config.h to define SENSORS.

Sensor connections on SX1272MB2xAS:

D8 D9: buttonRX TX: (unused)A3 A4: Rotary Angle Sensor
D6 D7: RGB LEDSCL SDA: digital light sensorA1 A2: Rotary Angle Sensor

Digital input pin, state reported via uplink: PC8
Digital output pin, controlled via downlink: PC6
PWM out: PB_10

Jumper enables auto-repeated transmit: PC10 and PC12 on NUCLEO board, located on end of morpho headers nearby JP4.

Committer:
Wayne Roberts
Date:
Mon Jul 13 09:15:59 2020 -0700
Revision:
35:be452a242876
Parent:
34:9c8966cd66a2
remove old crypto

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 34:9c8966cd66a2 1 /* */
Wayne Roberts 34:9c8966cd66a2 2
dudmuck 0:8f0d0ae0a077 3 #include <math.h>
dudmuck 0:8f0d0ae0a077 4 #include "board.h"
Wayne Roberts 29:ad409c68c0a6 5 #include "radio.h"
dudmuck 0:8f0d0ae0a077 6
dudmuck 0:8f0d0ae0a077 7 #include "LoRaMacCrypto.h"
Wayne Roberts 31:6ed03f61af64 8 #include "LoRaMacSingle.h"
dudmuck 0:8f0d0ae0a077 9 #include "LoRaMacTest.h"
Wayne Roberts 34:9c8966cd66a2 10
Wayne Roberts 29:ad409c68c0a6 11 #define BEACONS_MISSED_LIMIT 16
dudmuck 16:915815632c1f 12
dudmuck 0:8f0d0ae0a077 13 #define PING_SLOT_RESOLUTION_us 30000
dudmuck 0:8f0d0ae0a077 14
Wayne Roberts 29:ad409c68c0a6 15 #define PREAMBLE_SYMBS 8
Wayne Roberts 29:ad409c68c0a6 16
Wayne Roberts 29:ad409c68c0a6 17 #define TARGET_PRECESSION_us 3000
Wayne Roberts 29:ad409c68c0a6 18 #define BEACON_RX_TIMEOUT_LOCKED_us 8000
Wayne Roberts 29:ad409c68c0a6 19
dudmuck 0:8f0d0ae0a077 20 /*!
dudmuck 0:8f0d0ae0a077 21 * Maximum PHY layer payload size
dudmuck 0:8f0d0ae0a077 22 */
dudmuck 0:8f0d0ae0a077 23 #define LORAMAC_PHY_MAXPAYLOAD 255
dudmuck 0:8f0d0ae0a077 24
dudmuck 0:8f0d0ae0a077 25 /*!
dudmuck 0:8f0d0ae0a077 26 * Maximum MAC commands buffer size
dudmuck 0:8f0d0ae0a077 27 */
dudmuck 0:8f0d0ae0a077 28 #define LORA_MAC_COMMAND_MAX_LENGTH 15
dudmuck 0:8f0d0ae0a077 29
Wayne Roberts 34:9c8966cd66a2 30 LowPowerClock::time_point txDoneAt;
dudmuck 20:42839629a5dc 31
dudmuck 0:8f0d0ae0a077 32 /*!
dudmuck 0:8f0d0ae0a077 33 * Device IEEE EUI
dudmuck 0:8f0d0ae0a077 34 */
dudmuck 0:8f0d0ae0a077 35 static uint8_t *LoRaMacDevEui;
dudmuck 0:8f0d0ae0a077 36
dudmuck 0:8f0d0ae0a077 37 /*!
dudmuck 0:8f0d0ae0a077 38 * Application IEEE EUI
dudmuck 0:8f0d0ae0a077 39 */
dudmuck 0:8f0d0ae0a077 40 static uint8_t *LoRaMacAppEui;
dudmuck 0:8f0d0ae0a077 41
dudmuck 0:8f0d0ae0a077 42 /*!
dudmuck 0:8f0d0ae0a077 43 * AES encryption/decryption cipher application key
dudmuck 0:8f0d0ae0a077 44 */
dudmuck 0:8f0d0ae0a077 45 static uint8_t *LoRaMacAppKey;
dudmuck 0:8f0d0ae0a077 46
dudmuck 0:8f0d0ae0a077 47 /*!
dudmuck 0:8f0d0ae0a077 48 * AES encryption/decryption cipher network session key
dudmuck 0:8f0d0ae0a077 49 */
dudmuck 0:8f0d0ae0a077 50 static uint8_t LoRaMacNwkSKey[] =
dudmuck 0:8f0d0ae0a077 51 {
dudmuck 0:8f0d0ae0a077 52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
dudmuck 0:8f0d0ae0a077 53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
dudmuck 0:8f0d0ae0a077 54 };
dudmuck 0:8f0d0ae0a077 55
dudmuck 0:8f0d0ae0a077 56 /*!
dudmuck 0:8f0d0ae0a077 57 * AES encryption/decryption cipher application session key
dudmuck 0:8f0d0ae0a077 58 */
dudmuck 0:8f0d0ae0a077 59 static uint8_t LoRaMacAppSKey[] =
dudmuck 0:8f0d0ae0a077 60 {
dudmuck 0:8f0d0ae0a077 61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
dudmuck 0:8f0d0ae0a077 62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
dudmuck 0:8f0d0ae0a077 63 };
dudmuck 0:8f0d0ae0a077 64
dudmuck 0:8f0d0ae0a077 65 /*!
dudmuck 0:8f0d0ae0a077 66 * Device nonce is a random value extracted by issuing a sequence of RSSI
dudmuck 0:8f0d0ae0a077 67 * measurements
dudmuck 0:8f0d0ae0a077 68 */
dudmuck 0:8f0d0ae0a077 69 static uint16_t LoRaMacDevNonce;
dudmuck 0:8f0d0ae0a077 70
dudmuck 0:8f0d0ae0a077 71 /*!
dudmuck 0:8f0d0ae0a077 72 * Network ID ( 3 bytes )
dudmuck 0:8f0d0ae0a077 73 */
dudmuck 0:8f0d0ae0a077 74 static uint32_t LoRaMacNetID;
dudmuck 0:8f0d0ae0a077 75
dudmuck 0:8f0d0ae0a077 76 /*!
dudmuck 0:8f0d0ae0a077 77 * Mote Address
dudmuck 0:8f0d0ae0a077 78 */
dudmuck 0:8f0d0ae0a077 79 static uint32_t LoRaMacDevAddr;
dudmuck 0:8f0d0ae0a077 80
dudmuck 0:8f0d0ae0a077 81 /*!
dudmuck 0:8f0d0ae0a077 82 * Multicast channels linked list
dudmuck 0:8f0d0ae0a077 83 */
dudmuck 0:8f0d0ae0a077 84 static MulticastParams_t *MulticastChannels = NULL;
dudmuck 0:8f0d0ae0a077 85
dudmuck 0:8f0d0ae0a077 86 /*!
dudmuck 0:8f0d0ae0a077 87 * Indicates if the node is connected to a private or public network
dudmuck 0:8f0d0ae0a077 88 */
dudmuck 0:8f0d0ae0a077 89 static bool PublicNetwork;
dudmuck 0:8f0d0ae0a077 90
Wayne Roberts 29:ad409c68c0a6 91 uint8_t tx_buf_len;
Wayne Roberts 29:ad409c68c0a6 92
Wayne Roberts 29:ad409c68c0a6 93 static uint8_t rxFRMPayload[244];
dudmuck 0:8f0d0ae0a077 94
dudmuck 0:8f0d0ae0a077 95 /*!
dudmuck 0:8f0d0ae0a077 96 * LoRaMAC frame counter. Each time a packet is sent the counter is incremented.
dudmuck 0:8f0d0ae0a077 97 * Only the 16 LSB bits are sent
dudmuck 0:8f0d0ae0a077 98 */
dudmuck 0:8f0d0ae0a077 99 static uint32_t UpLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 100
dudmuck 0:8f0d0ae0a077 101 /*!
dudmuck 0:8f0d0ae0a077 102 * LoRaMAC frame counter. Each time a packet is received the counter is incremented.
dudmuck 0:8f0d0ae0a077 103 * Only the 16 LSB bits are received
dudmuck 0:8f0d0ae0a077 104 */
dudmuck 0:8f0d0ae0a077 105 static uint32_t DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 106
dudmuck 0:8f0d0ae0a077 107 /*!
dudmuck 0:8f0d0ae0a077 108 * Used for test purposes. Disables the opening of the reception windows.
dudmuck 0:8f0d0ae0a077 109 */
dudmuck 0:8f0d0ae0a077 110 static bool IsRxWindowsEnabled = true;
Wayne Roberts 34:9c8966cd66a2 111
Wayne Roberts 34:9c8966cd66a2 112 LowPowerTimeout rx_timeout;
Wayne Roberts 34:9c8966cd66a2 113
Wayne Roberts 34:9c8966cd66a2 114 /* how long this MCU (we're running on) takes to wake-up from deep-sleep */
Wayne Roberts 34:9c8966cd66a2 115 microseconds mcu_wakeup_latency;
Wayne Roberts 34:9c8966cd66a2 116
Wayne Roberts 34:9c8966cd66a2 117 LowPowerClock::time_point rx_timeout_setAt;
dudmuck 0:8f0d0ae0a077 118
dudmuck 0:8f0d0ae0a077 119 /*!
dudmuck 0:8f0d0ae0a077 120 * Indicates if the MAC layer wants to send MAC commands
dudmuck 0:8f0d0ae0a077 121 */
dudmuck 0:8f0d0ae0a077 122 static bool MacCommandsInNextTx = false;
dudmuck 0:8f0d0ae0a077 123
dudmuck 0:8f0d0ae0a077 124 /*!
dudmuck 0:8f0d0ae0a077 125 * Contains the current MacCommandsBuffer index
dudmuck 0:8f0d0ae0a077 126 */
dudmuck 0:8f0d0ae0a077 127 static uint8_t MacCommandsBufferIndex = 0;
dudmuck 0:8f0d0ae0a077 128
dudmuck 0:8f0d0ae0a077 129 /*!
dudmuck 0:8f0d0ae0a077 130 * Contains the current MacCommandsBuffer index for MAC commands to repeat
dudmuck 0:8f0d0ae0a077 131 */
dudmuck 0:8f0d0ae0a077 132 static uint8_t MacCommandsBufferToRepeatIndex = 0;
dudmuck 0:8f0d0ae0a077 133
dudmuck 0:8f0d0ae0a077 134 /*!
dudmuck 0:8f0d0ae0a077 135 * Buffer containing the MAC layer commands
dudmuck 0:8f0d0ae0a077 136 */
dudmuck 0:8f0d0ae0a077 137 static uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
dudmuck 0:8f0d0ae0a077 138
dudmuck 0:8f0d0ae0a077 139 /*!
dudmuck 0:8f0d0ae0a077 140 * Buffer containing the MAC layer commands which must be repeated
dudmuck 0:8f0d0ae0a077 141 */
dudmuck 0:8f0d0ae0a077 142 static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH];
dudmuck 0:8f0d0ae0a077 143
dudmuck 18:9ac71c0eb70d 144 #define BEACON_SIZE 6 /* bytes */
dudmuck 18:9ac71c0eb70d 145 #define BEACON_CHANNEL_DR LORAMAC_DEFAULT_DATARATE
dudmuck 18:9ac71c0eb70d 146
dudmuck 18:9ac71c0eb70d 147
Wayne Roberts 29:ad409c68c0a6 148 #ifdef SX128x_H
Wayne Roberts 29:ad409c68c0a6 149 // 0 1 2 3 4 5 6 7
Wayne Roberts 29:ad409c68c0a6 150 const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 6, 5 };
Wayne Roberts 29:ad409c68c0a6 151 #define SF_FROM_DR0 12 /* DR0 is sf12 */
Wayne Roberts 29:ad409c68c0a6 152 #define SF_FROM_DR1 11 /* DR1 is sf11 */
Wayne Roberts 29:ad409c68c0a6 153 #define SF_FROM_DR2 10 /* DR2 is sf10 */
Wayne Roberts 29:ad409c68c0a6 154 #define SF_FROM_DR3 9 /* DR3 is sf9 */
Wayne Roberts 29:ad409c68c0a6 155 #define SF_FROM_DR4 8 /* DR4 is sf8 */
Wayne Roberts 29:ad409c68c0a6 156 #define SF_FROM_DR5 7 /* DR5 is sf7 */
Wayne Roberts 29:ad409c68c0a6 157 #define SF_FROM_DR6 6 /* DR5 is sf6 */
Wayne Roberts 29:ad409c68c0a6 158 #define SF_FROM_DR7 5 /* DR7 is sf5 */
Wayne Roberts 29:ad409c68c0a6 159
Wayne Roberts 29:ad409c68c0a6 160
Wayne Roberts 29:ad409c68c0a6 161 const int8_t TxPowers[] = { 12, 5 };
Wayne Roberts 29:ad409c68c0a6 162 #define LORAMAC_FIRST_CHANNEL ( (uint32_t)2486.9e6 )
Wayne Roberts 29:ad409c68c0a6 163 #define LORAMAC_STEPWIDTH_CHANNEL ( (uint32_t)300e3 )
Wayne Roberts 30:1c35c4f56e50 164 #define LORA_MAX_NB_CHANNELS 8
Wayne Roberts 29:ad409c68c0a6 165
Wayne Roberts 29:ad409c68c0a6 166 #define LORA_BANDWIDTH_KHZ 200
Wayne Roberts 29:ad409c68c0a6 167
Wayne Roberts 29:ad409c68c0a6 168 /* end sx1280 */
Wayne Roberts 29:ad409c68c0a6 169 #elif defined( USE_BAND_915_SINGLE )
dudmuck 18:9ac71c0eb70d 170 /*!
dudmuck 18:9ac71c0eb70d 171 * Data rates table definition
Wayne Roberts 29:ad409c68c0a6 172 DR: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/
dudmuck 18:9ac71c0eb70d 173 const uint8_t Datarates[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
Wayne Roberts 29:ad409c68c0a6 174 #define SF_FROM_DR8 12
Wayne Roberts 29:ad409c68c0a6 175 #define SF_FROM_DR9 11
Wayne Roberts 29:ad409c68c0a6 176 #define SF_FROM_DR10 10
Wayne Roberts 29:ad409c68c0a6 177 #define SF_FROM_DR11 9
Wayne Roberts 29:ad409c68c0a6 178 #define SF_FROM_DR12 8
Wayne Roberts 29:ad409c68c0a6 179 #define SF_FROM_DR13 7
dudmuck 18:9ac71c0eb70d 180
dudmuck 18:9ac71c0eb70d 181 /*!
dudmuck 18:9ac71c0eb70d 182 * Tx output powers table definition
dudmuck 18:9ac71c0eb70d 183 */
dudmuck 23:a862b5601663 184 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
dudmuck 23:a862b5601663 185 const int8_t TxPowers[] = { 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0 };
dudmuck 18:9ac71c0eb70d 186 #define LORAMAC_FIRST_CHANNEL ( (uint32_t)910.0e6 )
dudmuck 18:9ac71c0eb70d 187 #define LORAMAC_STEPWIDTH_CHANNEL ( (uint32_t)800e3 )
dudmuck 18:9ac71c0eb70d 188 #define LORA_MAX_NB_CHANNELS 8
dudmuck 18:9ac71c0eb70d 189
Wayne Roberts 29:ad409c68c0a6 190 #define LORA_BANDWIDTH_KHZ 500
dudmuck 18:9ac71c0eb70d 191
dudmuck 18:9ac71c0eb70d 192 /* end us915 */
Wayne Roberts 29:ad409c68c0a6 193 #elif defined(USE_BAND_433)
Wayne Roberts 29:ad409c68c0a6 194 // DR: 0 1 2 3 4 5 6 7
dudmuck 18:9ac71c0eb70d 195 const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
Wayne Roberts 29:ad409c68c0a6 196 #define SF_FROM_DR0 12
Wayne Roberts 29:ad409c68c0a6 197 #define SF_FROM_DR1 11
Wayne Roberts 29:ad409c68c0a6 198 #define SF_FROM_DR2 10
Wayne Roberts 29:ad409c68c0a6 199 #define SF_FROM_DR3 9
Wayne Roberts 29:ad409c68c0a6 200 #define SF_FROM_DR4 8
Wayne Roberts 29:ad409c68c0a6 201 #define SF_FROM_DR5 7
Wayne Roberts 29:ad409c68c0a6 202
dudmuck 18:9ac71c0eb70d 203 const int8_t TxPowers[] = { 10, 7, 4, 1, -2, -5 };
Wayne Roberts 29:ad409c68c0a6 204 #define LORA_BANDWIDTH_KHZ 125
dudmuck 18:9ac71c0eb70d 205
dudmuck 18:9ac71c0eb70d 206 #define LORAMAC_FIRST_CHANNEL ( (uint32_t)433.32e6 )
dudmuck 18:9ac71c0eb70d 207 #define LORAMAC_STEPWIDTH_CHANNEL ( (uint32_t)200e3 )
Wayne Roberts 30:1c35c4f56e50 208 #define LORA_MAX_NB_CHANNELS 7
dudmuck 18:9ac71c0eb70d 209
dudmuck 18:9ac71c0eb70d 210 /* end USE_BAND_433 */
dudmuck 18:9ac71c0eb70d 211 #else
dudmuck 18:9ac71c0eb70d 212 #error "Please define a frequency band in the compiler options."
dudmuck 0:8f0d0ae0a077 213 #endif
dudmuck 0:8f0d0ae0a077 214
Wayne Roberts 29:ad409c68c0a6 215 #define _SF_FROM_DR(dr) SF_FROM_DR ## dr
Wayne Roberts 29:ad409c68c0a6 216 #define SF_FROM_DR_(x) _SF_FROM_DR(x)
Wayne Roberts 29:ad409c68c0a6 217
Wayne Roberts 29:ad409c68c0a6 218 #ifdef SX128x_H
Wayne Roberts 29:ad409c68c0a6 219
Wayne Roberts 30:1c35c4f56e50 220 #define FASTEST_SF 5
Wayne Roberts 30:1c35c4f56e50 221 /* ratio of symbol period to time from end of packet to RxDone interrupt */
Wayne Roberts 30:1c35c4f56e50 222 // sp 200KHz 160 320 640 1280 2560 5120 10240 20480
Wayne Roberts 30:1c35c4f56e50 223 // usLatency 200KHz implicit-6byte 90 228 436 880 2020 4200 8800 19300
Wayne Roberts 30:1c35c4f56e50 224 // SF: 5 6 7 8 9 10 11 12
Wayne Roberts 30:1c35c4f56e50 225 const float rxLatencyFactorFromSF[8] = { 0.56, 0.72, 0.68, 0.69, 0.79, 0.82, 0.86, 0.94 };
Wayne Roberts 29:ad409c68c0a6 226
Wayne Roberts 29:ad409c68c0a6 227 #elif defined(SX126x_H) || defined(SX127x_H)
Wayne Roberts 29:ad409c68c0a6 228
Wayne Roberts 30:1c35c4f56e50 229 #define FASTEST_SF 5
Wayne Roberts 30:1c35c4f56e50 230 /* ratio of symbol period to time from end of packet to RxDone interrupt */
Wayne Roberts 30:1c35c4f56e50 231 // sp 500KHz 64 128 256 512 1024 2048 4096 8192
Wayne Roberts 30:1c35c4f56e50 232 // usLatency 500KHz implicit-6byte 92 184 376 780 1680 3680 7720
Wayne Roberts 30:1c35c4f56e50 233 // SF: 5 6 7 8 9 10 11 12
Wayne Roberts 30:1c35c4f56e50 234 const float rxLatencyFactorFromSF[8] = { 0.72, 0.72, 0.72, 0.73, 0.76, 0.82, 0.90, 0.94 };
Wayne Roberts 29:ad409c68c0a6 235
Wayne Roberts 29:ad409c68c0a6 236 #endif /* SX126x_H || SX127x_H */
Wayne Roberts 29:ad409c68c0a6 237
dudmuck 18:9ac71c0eb70d 238 static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS]; // populated in init
dudmuck 18:9ac71c0eb70d 239
dudmuck 16:915815632c1f 240 #define BEACON_GUARD_us 2000000 // pre-beacon start
dudmuck 0:8f0d0ae0a077 241 #define BEACON_RESERVED_us 2120000 // post-beacon start
dudmuck 0:8f0d0ae0a077 242
Wayne Roberts 29:ad409c68c0a6 243 #define MIN_SYMBOL_TIMEOUT 8 // number of symbols to keep receiver open for
dudmuck 13:18de9ee3a461 244
dudmuck 0:8f0d0ae0a077 245 /*!
dudmuck 0:8f0d0ae0a077 246 * LoRaMac parameters
dudmuck 0:8f0d0ae0a077 247 */
dudmuck 0:8f0d0ae0a077 248 LoRaMacParams_t LoRaMacParams;
dudmuck 0:8f0d0ae0a077 249
dudmuck 0:8f0d0ae0a077 250 /*!
dudmuck 0:8f0d0ae0a077 251 * LoRaMac default parameters
dudmuck 0:8f0d0ae0a077 252 */
dudmuck 0:8f0d0ae0a077 253 LoRaMacParams_t LoRaMacParamsDefaults;
dudmuck 0:8f0d0ae0a077 254
dudmuck 0:8f0d0ae0a077 255 /*!
dudmuck 0:8f0d0ae0a077 256 * Uplink messages repetitions counter
dudmuck 0:8f0d0ae0a077 257 */
dudmuck 0:8f0d0ae0a077 258 static uint8_t ChannelsNbRepCounter = 0;
dudmuck 0:8f0d0ae0a077 259
dudmuck 0:8f0d0ae0a077 260 /*!
dudmuck 0:8f0d0ae0a077 261 * Current channel index
dudmuck 0:8f0d0ae0a077 262 */
dudmuck 0:8f0d0ae0a077 263 static uint8_t Channel;
dudmuck 0:8f0d0ae0a077 264
dudmuck 0:8f0d0ae0a077 265 /*!
dudmuck 0:8f0d0ae0a077 266 * LoRaMac upper layer event functions
dudmuck 0:8f0d0ae0a077 267 */
dudmuck 0:8f0d0ae0a077 268 static LoRaMacPrimitives_t *LoRaMacPrimitives;
dudmuck 0:8f0d0ae0a077 269
dudmuck 0:8f0d0ae0a077 270 /*!
dudmuck 0:8f0d0ae0a077 271 * LoRaMac upper layer callback functions
dudmuck 0:8f0d0ae0a077 272 */
dudmuck 0:8f0d0ae0a077 273 static LoRaMacCallback_t *LoRaMacCallbacks;
dudmuck 0:8f0d0ae0a077 274
dudmuck 0:8f0d0ae0a077 275 /*!
dudmuck 0:8f0d0ae0a077 276 * LoRaMac duty cycle delayed Tx timer
dudmuck 0:8f0d0ae0a077 277 */
Wayne Roberts 34:9c8966cd66a2 278 LowPowerTimeout tx_timeout;
dudmuck 0:8f0d0ae0a077 279
dudmuck 0:8f0d0ae0a077 280 /*!
dudmuck 0:8f0d0ae0a077 281 * LoRaMac reception windows delay
dudmuck 0:8f0d0ae0a077 282 * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
dudmuck 0:8f0d0ae0a077 283 * join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
dudmuck 0:8f0d0ae0a077 284 */
Wayne Roberts 34:9c8966cd66a2 285 microseconds RxWindowDelay_us;
dudmuck 0:8f0d0ae0a077 286
dudmuck 0:8f0d0ae0a077 287 typedef enum {
dudmuck 0:8f0d0ae0a077 288 BEACON_STATE_NONE = 0,
dudmuck 0:8f0d0ae0a077 289 BEACON_STATE_FIRST_ACQ,
dudmuck 0:8f0d0ae0a077 290 BEACON_STATE_ACQ_ERROR,
dudmuck 21:500ff43d8424 291 BEACON_STATE_LOCKED,
dudmuck 0:8f0d0ae0a077 292 } beacon_state_e;
dudmuck 0:8f0d0ae0a077 293
dudmuck 16:915815632c1f 294 static struct beacon_struct {
dudmuck 0:8f0d0ae0a077 295 int rx_precession_us; // positive: rxing before tx start, negative: rxing after tx start
Wayne Roberts 34:9c8966cd66a2 296 LowPowerClock::time_point rx_setup_at;
Wayne Roberts 34:9c8966cd66a2 297 LowPowerClock::time_point LastBeaconRxAt; // was LastBeaconRx_us, updated only at beacon reception
Wayne Roberts 34:9c8966cd66a2 298 LowPowerClock::time_point sendAt;
Wayne Roberts 34:9c8966cd66a2 299 microseconds lastSendAtErr;
dudmuck 13:18de9ee3a461 300 int last_BeaconRxTimerError_us;
dudmuck 13:18de9ee3a461 301 int known_working_BeaconRxTimerError_us;
dudmuck 0:8f0d0ae0a077 302
Wayne Roberts 29:ad409c68c0a6 303 unsigned symbol_period_us;
dudmuck 0:8f0d0ae0a077 304
dudmuck 0:8f0d0ae0a077 305 uint8_t Precess_symbols; // how many symbols we want to start receiver before expected transmitter
Wayne Roberts 29:ad409c68c0a6 306 uint16_t nSymbsTimeout;
Wayne Roberts 29:ad409c68c0a6 307 unsigned SymbolTimeout_us;
dudmuck 0:8f0d0ae0a077 308 uint8_t num_missed;
Wayne Roberts 30:1c35c4f56e50 309 uint8_t num_consecutive_ok;
dudmuck 0:8f0d0ae0a077 310
dudmuck 0:8f0d0ae0a077 311 beacon_state_e state;
dudmuck 0:8f0d0ae0a077 312
dudmuck 0:8f0d0ae0a077 313 uint16_t tx_slot_offset;
dudmuck 0:8f0d0ae0a077 314 uint16_t periodicity_slots;
Wayne Roberts 30:1c35c4f56e50 315 uint32_t beaconStartToRxDone;
Wayne Roberts 29:ad409c68c0a6 316 uint16_t sendOpportunities;
Wayne Roberts 29:ad409c68c0a6 317
Wayne Roberts 34:9c8966cd66a2 318 LowPowerTimeout timeout_rx;
Wayne Roberts 34:9c8966cd66a2 319 LowPowerTimeout timeout_guard;
dudmuck 16:915815632c1f 320 bool guard;
dudmuck 0:8f0d0ae0a077 321 } BeaconCtx;
dudmuck 0:8f0d0ae0a077 322
dudmuck 0:8f0d0ae0a077 323 /*!
dudmuck 0:8f0d0ae0a077 324 * Rx window parameters
dudmuck 0:8f0d0ae0a077 325 */
dudmuck 0:8f0d0ae0a077 326 typedef struct
dudmuck 0:8f0d0ae0a077 327 {
dudmuck 0:8f0d0ae0a077 328 int8_t Datarate;
dudmuck 0:8f0d0ae0a077 329 uint32_t RxWindowTimeout;
Wayne Roberts 29:ad409c68c0a6 330 } RxConfigParams_t;
dudmuck 0:8f0d0ae0a077 331
dudmuck 0:8f0d0ae0a077 332 /*!
dudmuck 0:8f0d0ae0a077 333 * Rx windows params
dudmuck 0:8f0d0ae0a077 334 */
dudmuck 0:8f0d0ae0a077 335 static RxConfigParams_t RxWindowsParam;
dudmuck 0:8f0d0ae0a077 336
dudmuck 0:8f0d0ae0a077 337 /*!
dudmuck 0:8f0d0ae0a077 338 * Acknowledge timeout timer. Used for packet retransmissions.
dudmuck 0:8f0d0ae0a077 339 */
dudmuck 0:8f0d0ae0a077 340 static LowPowerTimeout AckTimeoutTimer;
dudmuck 0:8f0d0ae0a077 341
dudmuck 0:8f0d0ae0a077 342 /*!
dudmuck 0:8f0d0ae0a077 343 * Number of trials for the Join Request
dudmuck 0:8f0d0ae0a077 344 */
dudmuck 0:8f0d0ae0a077 345 static uint8_t JoinRequestTrials;
dudmuck 0:8f0d0ae0a077 346
dudmuck 0:8f0d0ae0a077 347 /*!
dudmuck 0:8f0d0ae0a077 348 * Maximum number of trials for the Join Request
dudmuck 0:8f0d0ae0a077 349 */
dudmuck 0:8f0d0ae0a077 350 static uint8_t MaxJoinRequestTrials;
dudmuck 0:8f0d0ae0a077 351
dudmuck 0:8f0d0ae0a077 352 /*!
dudmuck 0:8f0d0ae0a077 353 * Structure to hold an MCPS indication data.
dudmuck 0:8f0d0ae0a077 354 */
dudmuck 0:8f0d0ae0a077 355 static McpsIndication_t McpsIndication;
dudmuck 0:8f0d0ae0a077 356
dudmuck 0:8f0d0ae0a077 357 /*!
dudmuck 0:8f0d0ae0a077 358 * Structure to hold MCPS confirm data.
dudmuck 0:8f0d0ae0a077 359 */
dudmuck 0:8f0d0ae0a077 360 static McpsConfirm_t McpsConfirm;
dudmuck 0:8f0d0ae0a077 361
dudmuck 0:8f0d0ae0a077 362 /*!
dudmuck 0:8f0d0ae0a077 363 * Structure to hold MLME confirm data.
dudmuck 0:8f0d0ae0a077 364 */
dudmuck 0:8f0d0ae0a077 365 static MlmeConfirm_t MlmeConfirm;
dudmuck 0:8f0d0ae0a077 366
dudmuck 0:8f0d0ae0a077 367 /*!
dudmuck 0:8f0d0ae0a077 368 * Structure to hold MLME indication data.
dudmuck 0:8f0d0ae0a077 369 */
dudmuck 0:8f0d0ae0a077 370 static MlmeIndication_t MlmeIndication;
dudmuck 0:8f0d0ae0a077 371
dudmuck 0:8f0d0ae0a077 372 /*!
dudmuck 0:8f0d0ae0a077 373 * LoRaMac tx/rx operation state
dudmuck 0:8f0d0ae0a077 374 */
Wayne Roberts 29:ad409c68c0a6 375 volatile LoRaMacFlags_t LoRaMacFlags;
dudmuck 0:8f0d0ae0a077 376
dudmuck 0:8f0d0ae0a077 377 /*!
dudmuck 0:8f0d0ae0a077 378 * \brief This function prepares the MAC to abort the execution of function
dudmuck 0:8f0d0ae0a077 379 * OnRadioRxDone in case of a reception error.
dudmuck 0:8f0d0ae0a077 380 */
dudmuck 0:8f0d0ae0a077 381 static void PrepareRxDoneAbort( void );
dudmuck 0:8f0d0ae0a077 382
dudmuck 0:8f0d0ae0a077 383 /*!
dudmuck 0:8f0d0ae0a077 384 * \brief Function executed on Radio Tx Timeout event
dudmuck 0:8f0d0ae0a077 385 */
dudmuck 0:8f0d0ae0a077 386 static void OnRadioTxTimeout( void );
dudmuck 0:8f0d0ae0a077 387
dudmuck 0:8f0d0ae0a077 388 /*!
dudmuck 0:8f0d0ae0a077 389 * \brief Function executed on Radio Rx error event
dudmuck 0:8f0d0ae0a077 390 */
dudmuck 0:8f0d0ae0a077 391 static void OnRadioRxError( void );
dudmuck 0:8f0d0ae0a077 392
dudmuck 0:8f0d0ae0a077 393 /*!
dudmuck 0:8f0d0ae0a077 394 * \brief Function executed on Radio Rx Timeout event
dudmuck 0:8f0d0ae0a077 395 */
dudmuck 0:8f0d0ae0a077 396 static void OnRadioRxTimeout( void );
dudmuck 0:8f0d0ae0a077 397
dudmuck 0:8f0d0ae0a077 398 /*!
dudmuck 0:8f0d0ae0a077 399 * \brief Function executed on AckTimeout timer event
dudmuck 0:8f0d0ae0a077 400 */
dudmuck 0:8f0d0ae0a077 401 static void OnAckTimeoutTimerEvent( void );
dudmuck 0:8f0d0ae0a077 402
dudmuck 0:8f0d0ae0a077 403 /*!
dudmuck 0:8f0d0ae0a077 404 * \brief Adds a new MAC command to be sent.
dudmuck 0:8f0d0ae0a077 405 *
dudmuck 0:8f0d0ae0a077 406 * \Remark MAC layer internal function
dudmuck 0:8f0d0ae0a077 407 *
dudmuck 0:8f0d0ae0a077 408 * \param [in] cmd MAC command to be added
dudmuck 0:8f0d0ae0a077 409 * [MOTE_MAC_LINK_CHECK_REQ,
dudmuck 0:8f0d0ae0a077 410 * MOTE_MAC_LINK_ADR_ANS,
dudmuck 0:8f0d0ae0a077 411 * MOTE_MAC_DUTY_CYCLE_ANS,
dudmuck 0:8f0d0ae0a077 412 * MOTE_MAC_RX2_PARAM_SET_ANS,
dudmuck 0:8f0d0ae0a077 413 * MOTE_MAC_DEV_STATUS_ANS
dudmuck 0:8f0d0ae0a077 414 * MOTE_MAC_NEW_CHANNEL_ANS]
dudmuck 0:8f0d0ae0a077 415 * \param [in] p1 1st parameter ( optional depends on the command )
dudmuck 0:8f0d0ae0a077 416 * \param [in] p2 2nd parameter ( optional depends on the command )
dudmuck 0:8f0d0ae0a077 417 *
dudmuck 0:8f0d0ae0a077 418 * \retval status Function status [0: OK, 1: Unknown command, 2: Buffer full]
dudmuck 0:8f0d0ae0a077 419 */
dudmuck 0:8f0d0ae0a077 420 static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 );
dudmuck 0:8f0d0ae0a077 421
dudmuck 0:8f0d0ae0a077 422 /*!
dudmuck 0:8f0d0ae0a077 423 * \brief Parses the MAC commands which must be repeated.
dudmuck 0:8f0d0ae0a077 424 *
dudmuck 0:8f0d0ae0a077 425 * \Remark MAC layer internal function
dudmuck 0:8f0d0ae0a077 426 *
dudmuck 0:8f0d0ae0a077 427 * \param [IN] cmdBufIn Buffer which stores the MAC commands to send
dudmuck 0:8f0d0ae0a077 428 * \param [IN] length Length of the input buffer to parse
dudmuck 0:8f0d0ae0a077 429 * \param [OUT] cmdBufOut Buffer which stores the MAC commands which must be
dudmuck 0:8f0d0ae0a077 430 * repeated.
dudmuck 0:8f0d0ae0a077 431 *
dudmuck 0:8f0d0ae0a077 432 * \retval Size of the MAC commands to repeat.
dudmuck 0:8f0d0ae0a077 433 */
dudmuck 0:8f0d0ae0a077 434 static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut );
dudmuck 0:8f0d0ae0a077 435
dudmuck 0:8f0d0ae0a077 436 /*!
dudmuck 0:8f0d0ae0a077 437 * \brief Verifies, if a value is in a given range.
dudmuck 0:8f0d0ae0a077 438 *
dudmuck 0:8f0d0ae0a077 439 * \param value Value to verify, if it is in range
dudmuck 0:8f0d0ae0a077 440 *
dudmuck 0:8f0d0ae0a077 441 * \param min Minimum possible value
dudmuck 0:8f0d0ae0a077 442 *
dudmuck 0:8f0d0ae0a077 443 * \param max Maximum possible value
dudmuck 0:8f0d0ae0a077 444 *
dudmuck 0:8f0d0ae0a077 445 * \retval Returns the maximum valid tx power
dudmuck 0:8f0d0ae0a077 446 */
dudmuck 0:8f0d0ae0a077 447 static bool ValueInRange( int8_t value, int8_t min, int8_t max );
dudmuck 0:8f0d0ae0a077 448
dudmuck 0:8f0d0ae0a077 449
dudmuck 0:8f0d0ae0a077 450 /*!
dudmuck 0:8f0d0ae0a077 451 * \brief Decodes MAC commands in the fOpts field and in the payload
dudmuck 0:8f0d0ae0a077 452 */
dudmuck 0:8f0d0ae0a077 453 static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr );
dudmuck 0:8f0d0ae0a077 454
dudmuck 0:8f0d0ae0a077 455 /*!
dudmuck 0:8f0d0ae0a077 456 * \brief LoRaMAC layer generic send frame
dudmuck 0:8f0d0ae0a077 457 *
dudmuck 0:8f0d0ae0a077 458 * \param [IN] macHdr MAC header field
dudmuck 0:8f0d0ae0a077 459 * \param [IN] fPort MAC payload port
dudmuck 0:8f0d0ae0a077 460 * \param [IN] fBuffer MAC data buffer to be sent
dudmuck 0:8f0d0ae0a077 461 * \param [IN] fBufferSize MAC data buffer size
dudmuck 0:8f0d0ae0a077 462 * \retval status Status of the operation.
dudmuck 0:8f0d0ae0a077 463 */
dudmuck 0:8f0d0ae0a077 464 LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
dudmuck 0:8f0d0ae0a077 465
dudmuck 0:8f0d0ae0a077 466 /*!
dudmuck 0:8f0d0ae0a077 467 * \brief LoRaMAC layer frame buffer initialization
dudmuck 0:8f0d0ae0a077 468 *
dudmuck 0:8f0d0ae0a077 469 * \param [IN] macHdr MAC header field
dudmuck 0:8f0d0ae0a077 470 * \param [IN] fCtrl MAC frame control field
dudmuck 0:8f0d0ae0a077 471 * \param [IN] fOpts MAC commands buffer
dudmuck 0:8f0d0ae0a077 472 * \param [IN] fPort MAC payload port
dudmuck 0:8f0d0ae0a077 473 * \param [IN] fBuffer MAC data buffer to be sent
dudmuck 0:8f0d0ae0a077 474 * \param [IN] fBufferSize MAC data buffer size
dudmuck 0:8f0d0ae0a077 475 * \retval status Status of the operation.
dudmuck 0:8f0d0ae0a077 476 */
dudmuck 0:8f0d0ae0a077 477 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
dudmuck 0:8f0d0ae0a077 478
dudmuck 0:8f0d0ae0a077 479 /*!
dudmuck 0:8f0d0ae0a077 480 * \brief Sets the radio in continuous transmission mode
dudmuck 0:8f0d0ae0a077 481 *
dudmuck 0:8f0d0ae0a077 482 * \remark Uses the radio parameters set on the previous transmission.
dudmuck 0:8f0d0ae0a077 483 *
dudmuck 0:8f0d0ae0a077 484 * \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode
dudmuck 0:8f0d0ae0a077 485 * \retval status Status of the operation.
dudmuck 0:8f0d0ae0a077 486 */
dudmuck 0:8f0d0ae0a077 487 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout );
dudmuck 0:8f0d0ae0a077 488
dudmuck 0:8f0d0ae0a077 489 /*!
dudmuck 0:8f0d0ae0a077 490 * \brief Sets the radio in continuous transmission mode
dudmuck 0:8f0d0ae0a077 491 *
dudmuck 0:8f0d0ae0a077 492 * \remark Uses the radio parameters set on the previous transmission.
dudmuck 0:8f0d0ae0a077 493 *
dudmuck 0:8f0d0ae0a077 494 * \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode
dudmuck 0:8f0d0ae0a077 495 * \param [IN] frequency RF frequency to be set.
dudmuck 0:8f0d0ae0a077 496 * \param [IN] power RF ouptput power to be set.
dudmuck 0:8f0d0ae0a077 497 * \retval status Status of the operation.
dudmuck 0:8f0d0ae0a077 498 */
dudmuck 0:8f0d0ae0a077 499 LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power );
dudmuck 0:8f0d0ae0a077 500
Wayne Roberts 29:ad409c68c0a6 501 #ifdef SX127x_H
Wayne Roberts 29:ad409c68c0a6 502 void printLoraIrqs(bool clear)
Wayne Roberts 29:ad409c68c0a6 503 {
Wayne Roberts 34:9c8966cd66a2 504 pc_printf("\r\nIrqFlags:");
Wayne Roberts 29:ad409c68c0a6 505 if (Radio::lora.RegIrqFlags.bits.CadDetected)
Wayne Roberts 34:9c8966cd66a2 506 pc_printf("CadDetected ");
Wayne Roberts 29:ad409c68c0a6 507 if (Radio::lora.RegIrqFlags.bits.FhssChangeChannel) {
Wayne Roberts 34:9c8966cd66a2 508 pc_printf("FhssChangeChannel:%d ", Radio::lora.RegHopChannel.bits.FhssPresentChannel);
Wayne Roberts 29:ad409c68c0a6 509 }
Wayne Roberts 29:ad409c68c0a6 510 if (Radio::lora.RegIrqFlags.bits.CadDone)
Wayne Roberts 34:9c8966cd66a2 511 pc_printf("CadDone ");
Wayne Roberts 29:ad409c68c0a6 512 if (Radio::lora.RegIrqFlags.bits.TxDone)
Wayne Roberts 34:9c8966cd66a2 513 pc_printf("TxDone-dio0:%d ", Radio::radio.dio0.read());
Wayne Roberts 29:ad409c68c0a6 514 if (Radio::lora.RegIrqFlags.bits.ValidHeader)
Wayne Roberts 34:9c8966cd66a2 515 pc_printf("ValidHeader ");
Wayne Roberts 29:ad409c68c0a6 516 if (Radio::lora.RegIrqFlags.bits.PayloadCrcError)
Wayne Roberts 34:9c8966cd66a2 517 pc_printf("PayloadCrcError ");
Wayne Roberts 29:ad409c68c0a6 518 if (Radio::lora.RegIrqFlags.bits.RxDone)
Wayne Roberts 34:9c8966cd66a2 519 pc_printf("RxDone ");
Wayne Roberts 29:ad409c68c0a6 520 if (Radio::lora.RegIrqFlags.bits.RxTimeout)
Wayne Roberts 34:9c8966cd66a2 521 pc_printf("RxTimeout ");
Wayne Roberts 34:9c8966cd66a2 522
Wayne Roberts 34:9c8966cd66a2 523 pc_printf("\r\n");
Wayne Roberts 29:ad409c68c0a6 524
Wayne Roberts 29:ad409c68c0a6 525 if (clear)
Wayne Roberts 29:ad409c68c0a6 526 Radio::radio.write_reg(REG_LR_IRQFLAGS, Radio::lora.RegIrqFlags.octet);
Wayne Roberts 29:ad409c68c0a6 527 }
Wayne Roberts 29:ad409c68c0a6 528
Wayne Roberts 29:ad409c68c0a6 529 void printOpMode()
Wayne Roberts 29:ad409c68c0a6 530 {
Wayne Roberts 29:ad409c68c0a6 531 Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
Wayne Roberts 29:ad409c68c0a6 532 switch (Radio::radio.RegOpMode.bits.Mode) {
Wayne Roberts 34:9c8966cd66a2 533 case RF_OPMODE_SLEEP: pc_printf("sleep"); break;
Wayne Roberts 34:9c8966cd66a2 534 case RF_OPMODE_STANDBY: pc_printf("stby"); break;
Wayne Roberts 34:9c8966cd66a2 535 case RF_OPMODE_SYNTHESIZER_TX: pc_printf("fstx"); break;
Wayne Roberts 34:9c8966cd66a2 536 case RF_OPMODE_TRANSMITTER: pc_printf("tx"); break;
Wayne Roberts 34:9c8966cd66a2 537 case RF_OPMODE_SYNTHESIZER_RX: pc_printf("fsrx"); break;
Wayne Roberts 34:9c8966cd66a2 538 case RF_OPMODE_RECEIVER: pc_printf("rx"); break;
Wayne Roberts 29:ad409c68c0a6 539 case 6:
Wayne Roberts 29:ad409c68c0a6 540 if (Radio::radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 34:9c8966cd66a2 541 pc_printf("rxs");
Wayne Roberts 29:ad409c68c0a6 542 else
Wayne Roberts 34:9c8966cd66a2 543 pc_printf("-6-");
Wayne Roberts 29:ad409c68c0a6 544 break; // todo: different lora/fsk
Wayne Roberts 29:ad409c68c0a6 545 case 7:
Wayne Roberts 29:ad409c68c0a6 546 if (Radio::radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 34:9c8966cd66a2 547 pc_printf("cad");
Wayne Roberts 29:ad409c68c0a6 548 else
Wayne Roberts 34:9c8966cd66a2 549 pc_printf("-7-");
Wayne Roberts 29:ad409c68c0a6 550 break; // todo: different lora/fsk
Wayne Roberts 29:ad409c68c0a6 551 }
Wayne Roberts 29:ad409c68c0a6 552 }
Wayne Roberts 29:ad409c68c0a6 553 #endif /* SX127x_H */
Wayne Roberts 29:ad409c68c0a6 554
dudmuck 0:8f0d0ae0a077 555 /*!
dudmuck 0:8f0d0ae0a077 556 * \brief Resets MAC specific parameters to default
dudmuck 0:8f0d0ae0a077 557 */
dudmuck 0:8f0d0ae0a077 558 static void ResetMacParameters( void );
dudmuck 0:8f0d0ae0a077 559
dudmuck 0:8f0d0ae0a077 560 void
dudmuck 0:8f0d0ae0a077 561 loramac_print_status()
dudmuck 0:8f0d0ae0a077 562 {
Wayne Roberts 34:9c8966cd66a2 563 int until_beacon = BeaconCtx.rx_setup_at.time_since_epoch().count() - LowPowerClock::now().time_since_epoch().count();
Wayne Roberts 29:ad409c68c0a6 564 mac_printf("until_beacon:%d ", until_beacon);
Wayne Roberts 29:ad409c68c0a6 565 mac_printf("DR%u=sf%u guard:%d\r\n",
dudmuck 16:915815632c1f 566 LoRaMacParams.ChannelsDatarate_fixed,
dudmuck 16:915815632c1f 567 Datarates[LoRaMacParams.ChannelsDatarate_fixed],
dudmuck 16:915815632c1f 568 BeaconCtx.guard
dudmuck 16:915815632c1f 569 );
Wayne Roberts 29:ad409c68c0a6 570 #ifdef SX128x_H
Wayne Roberts 29:ad409c68c0a6 571 status_t status;
Wayne Roberts 29:ad409c68c0a6 572 Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
Wayne Roberts 29:ad409c68c0a6 573 switch (status.bits.cmdStatus) {
Wayne Roberts 34:9c8966cd66a2 574 case 1: pc_printf("success"); break;
Wayne Roberts 34:9c8966cd66a2 575 case 2: pc_printf("dataAvail"); break;
Wayne Roberts 34:9c8966cd66a2 576 case 3: pc_printf("cmdTimeout"); break;
Wayne Roberts 34:9c8966cd66a2 577 case 4: pc_printf("cmdErr"); break;
Wayne Roberts 34:9c8966cd66a2 578 case 5: pc_printf("exeFail"); break;
Wayne Roberts 34:9c8966cd66a2 579 case 6: pc_printf("txdone"); break;
Wayne Roberts 34:9c8966cd66a2 580 default: pc_printf("cmdStatus:<%u>", status.bits.cmdStatus); break;
Wayne Roberts 29:ad409c68c0a6 581 }
Wayne Roberts 34:9c8966cd66a2 582 pc_printf(" ");
Wayne Roberts 29:ad409c68c0a6 583 switch (status.bits.chipMode) {
Wayne Roberts 34:9c8966cd66a2 584 case 2: pc_printf("stdby_rc"); break;
Wayne Roberts 34:9c8966cd66a2 585 case 3: pc_printf("stdby_xosc"); break;
Wayne Roberts 34:9c8966cd66a2 586 case 4: pc_printf("fs"); break;
Wayne Roberts 34:9c8966cd66a2 587 case 5: pc_printf("\e[32mrx\e[0m"); break;
Wayne Roberts 34:9c8966cd66a2 588 case 6: pc_printf("\e[31mtx\e[0m"); break;
Wayne Roberts 34:9c8966cd66a2 589 default: pc_printf("chipMode:<%u>", status.bits.chipMode); break;
Wayne Roberts 29:ad409c68c0a6 590 }
Wayne Roberts 29:ad409c68c0a6 591 LoRaPktPar0_t LoRaPktPar0;
Wayne Roberts 29:ad409c68c0a6 592 LoRaPktPar0.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
Wayne Roberts 34:9c8966cd66a2 593 pc_printf(" bw:%u sf%u ", LoRaPktPar0.bits.modem_bw, LoRaPktPar0.bits.modem_sf);
Wayne Roberts 29:ad409c68c0a6 594 mac_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
Wayne Roberts 29:ad409c68c0a6 595 #elif defined(SX127x_H)
Wayne Roberts 29:ad409c68c0a6 596 Radio::radio.RegPaConfig.octet = Radio::radio.read_reg(REG_PACONFIG);
Wayne Roberts 29:ad409c68c0a6 597 if (Radio::radio.RegPaConfig.bits.PaSelect)
Wayne Roberts 34:9c8966cd66a2 598 pc_printf("PA_BOOST ");
Wayne Roberts 29:ad409c68c0a6 599 else
Wayne Roberts 34:9c8966cd66a2 600 pc_printf("RFO ");
Wayne Roberts 29:ad409c68c0a6 601
Wayne Roberts 29:ad409c68c0a6 602 Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
Wayne Roberts 34:9c8966cd66a2 603 pc_printf("%.3fMHz sf%ubw%u ", Radio::radio.get_frf_MHz(), Radio::lora.getSf(), Radio::lora.getBw());
Wayne Roberts 34:9c8966cd66a2 604 pc_printf("dio0pin:%u ", Radio::radio.dio0.read());
Wayne Roberts 29:ad409c68c0a6 605 printOpMode();
Wayne Roberts 29:ad409c68c0a6 606 if (!Radio::radio.RegOpMode.bits.LongRangeMode) {
Wayne Roberts 34:9c8966cd66a2 607 pc_printf("FSK\r\n");
Wayne Roberts 29:ad409c68c0a6 608 return;
Wayne Roberts 29:ad409c68c0a6 609 }
Wayne Roberts 29:ad409c68c0a6 610
Wayne Roberts 29:ad409c68c0a6 611 Radio::lora.RegIrqFlags.octet = Radio::radio.read_reg(REG_LR_IRQFLAGS);
Wayne Roberts 29:ad409c68c0a6 612 printLoraIrqs(false);
Wayne Roberts 29:ad409c68c0a6 613
Wayne Roberts 29:ad409c68c0a6 614 Radio::lora.RegTest33.octet = Radio::radio.read_reg(REG_LR_TEST33); // invert_i_q
Wayne Roberts 29:ad409c68c0a6 615 Radio::lora.RegDriftInvert.octet = Radio::radio.read_reg(REG_LR_DRIFT_INVERT);
Wayne Roberts 34:9c8966cd66a2 616 pc_printf("modemstat:%02x, rxinv:%x,%x\r\n", Radio::radio.read_reg(REG_LR_MODEMSTAT), Radio::lora.RegTest33.octet, Radio::lora.RegDriftInvert.octet);
Wayne Roberts 29:ad409c68c0a6 617 Radio::radio.RegDioMapping1.octet = Radio::radio.read_reg(REG_DIOMAPPING1);
Wayne Roberts 34:9c8966cd66a2 618 pc_printf("\r\ndio0map:%u\r\n", Radio::radio.RegDioMapping1.bits.Dio0Mapping);
Wayne Roberts 34:9c8966cd66a2 619 pc_printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", Radio::radio.read_reg(REG_LR_FIFOADDRPTR), Radio::radio.read_reg(REG_LR_FIFORXBASEADDR));
Wayne Roberts 29:ad409c68c0a6 620 #elif defined(SX126x_H)
Wayne Roberts 29:ad409c68c0a6 621 status_t status;
Wayne Roberts 29:ad409c68c0a6 622 Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
Wayne Roberts 29:ad409c68c0a6 623 switch (status.bits.chipMode) {
Wayne Roberts 29:ad409c68c0a6 624 case 2: mac_printf("STBY_RC"); break;
Wayne Roberts 29:ad409c68c0a6 625 case 3: mac_printf("STBY_XOSC"); break;
Wayne Roberts 29:ad409c68c0a6 626 case 4: mac_printf("FS"); break;
Wayne Roberts 29:ad409c68c0a6 627 case 5: mac_printf("RX"); break;
Wayne Roberts 29:ad409c68c0a6 628 case 6: mac_printf("TX"); break;
Wayne Roberts 29:ad409c68c0a6 629 default: mac_printf("%u", status.bits.chipMode); break;
Wayne Roberts 29:ad409c68c0a6 630 }
Wayne Roberts 34:9c8966cd66a2 631 pc_printf(" ");
Wayne Roberts 29:ad409c68c0a6 632 switch (status.bits.cmdStatus) {
Wayne Roberts 29:ad409c68c0a6 633 case 1: mac_printf("rfu"); break;
Wayne Roberts 29:ad409c68c0a6 634 case 2: mac_printf("dataAvail"); break;
Wayne Roberts 29:ad409c68c0a6 635 case 3: mac_printf("timeout"); break;
Wayne Roberts 29:ad409c68c0a6 636 case 4: mac_printf("err"); break;
Wayne Roberts 29:ad409c68c0a6 637 case 5: mac_printf("fail"); break;
Wayne Roberts 29:ad409c68c0a6 638 case 6: mac_printf("txdone"); break;
Wayne Roberts 29:ad409c68c0a6 639 default: mac_printf("%u", status.bits.cmdStatus); break;
Wayne Roberts 29:ad409c68c0a6 640 }
Wayne Roberts 29:ad409c68c0a6 641 loraConfig0_t conf0;
Wayne Roberts 29:ad409c68c0a6 642 conf0.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG0, 1);
Wayne Roberts 29:ad409c68c0a6 643 // bw7=125 bw8=250 b9=500
Wayne Roberts 29:ad409c68c0a6 644 mac_printf(" bw:%u sf%u\r\n", conf0.bits.modem_bw, conf0.bits.modem_sf);
Wayne Roberts 29:ad409c68c0a6 645 loraConfig1_t conf1;
Wayne Roberts 29:ad409c68c0a6 646 conf1.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG1, 1);
Wayne Roberts 29:ad409c68c0a6 647 mac_printf("inviq:%u cr%u\r\n", conf1.bits.rx_invert_iq, conf1.bits.tx_coding_rate);
Wayne Roberts 29:ad409c68c0a6 648 mac_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
Wayne Roberts 29:ad409c68c0a6 649 #endif /* ..SX126x_H */
dudmuck 0:8f0d0ae0a077 650 }
dudmuck 0:8f0d0ae0a077 651
Wayne Roberts 29:ad409c68c0a6 652 static void RxWindowSetup( uint32_t freq, int8_t datarate, uint16_t timeout, bool rxContinuous )
Wayne Roberts 29:ad409c68c0a6 653 {
Wayne Roberts 29:ad409c68c0a6 654 uint8_t downlinkDatarate = Datarates[datarate];
Wayne Roberts 29:ad409c68c0a6 655
Wayne Roberts 29:ad409c68c0a6 656 Radio::SetChannel( freq );
Wayne Roberts 29:ad409c68c0a6 657
Wayne Roberts 29:ad409c68c0a6 658 // Store downlink datarate
Wayne Roberts 29:ad409c68c0a6 659 McpsIndication.RxDatarate = ( uint8_t ) datarate;
Wayne Roberts 29:ad409c68c0a6 660
Wayne Roberts 29:ad409c68c0a6 661 Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, downlinkDatarate, 1);
Wayne Roberts 29:ad409c68c0a6 662
Wayne Roberts 29:ad409c68c0a6 663 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 29:ad409c68c0a6 664 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, false, true);
Wayne Roberts 29:ad409c68c0a6 665 Radio::SetLoRaSymbolTimeout(timeout);
Wayne Roberts 29:ad409c68c0a6 666 Radio::SetRxMaxPayloadLength(LORAMAC_PHY_MAXPAYLOAD);
Wayne Roberts 29:ad409c68c0a6 667
Wayne Roberts 29:ad409c68c0a6 668 } // ..RxWindowSetup()
Wayne Roberts 29:ad409c68c0a6 669
Wayne Roberts 29:ad409c68c0a6 670 static void OnRxWindowTimerEvent( void )
Wayne Roberts 29:ad409c68c0a6 671 {
Wayne Roberts 29:ad409c68c0a6 672 RxWindowSetup(Channels[Channel].Frequency, RxWindowsParam.Datarate, RxWindowsParam.RxWindowTimeout, false);
Wayne Roberts 29:ad409c68c0a6 673 Radio::Rx( LoRaMacParams.MaxRxWindow );
Wayne Roberts 29:ad409c68c0a6 674 }
Wayne Roberts 29:ad409c68c0a6 675
dudmuck 0:8f0d0ae0a077 676 static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError );
dudmuck 0:8f0d0ae0a077 677
Wayne Roberts 34:9c8966cd66a2 678 LowPowerClock::time_point rxto_irqAt;
Wayne Roberts 33:bc0b6be19e07 679
Wayne Roberts 33:bc0b6be19e07 680 static void OnRadioTxDone_topHalf()
Wayne Roberts 33:bc0b6be19e07 681 {
Wayne Roberts 34:9c8966cd66a2 682 rxto_irqAt = LowPowerClock::now();
Wayne Roberts 33:bc0b6be19e07 683 }
Wayne Roberts 33:bc0b6be19e07 684
Wayne Roberts 29:ad409c68c0a6 685 static void OnRadioTxDone_bh()
dudmuck 0:8f0d0ae0a077 686 {
dudmuck 0:8f0d0ae0a077 687 // Setup timers
dudmuck 16:915815632c1f 688 if (IsRxWindowsEnabled)
dudmuck 0:8f0d0ae0a077 689 {
Wayne Roberts 34:9c8966cd66a2 690 rx_timeout_setAt = rxto_irqAt + RxWindowDelay_us;
Wayne Roberts 34:9c8966cd66a2 691 rx_timeout.attach_absolute(&OnRxWindowTimerEvent, rx_timeout_setAt);
Wayne Roberts 29:ad409c68c0a6 692 if (LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 693 {
Wayne Roberts 34:9c8966cd66a2 694 microseconds us(ACK_TIMEOUT_us + randr(-ACK_TIMEOUT_RND_us, ACK_TIMEOUT_RND_us));
Wayne Roberts 34:9c8966cd66a2 695 us += RxWindowDelay_us;
Wayne Roberts 34:9c8966cd66a2 696 AckTimeoutTimer.attach(&OnAckTimeoutTimerEvent, us - mcu_wakeup_latency);
dudmuck 0:8f0d0ae0a077 697 }
dudmuck 0:8f0d0ae0a077 698 }
dudmuck 0:8f0d0ae0a077 699 else
dudmuck 0:8f0d0ae0a077 700 {
dudmuck 0:8f0d0ae0a077 701 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 702 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 703
dudmuck 0:8f0d0ae0a077 704 if( LoRaMacFlags.Value == 0 )
dudmuck 0:8f0d0ae0a077 705 {
dudmuck 0:8f0d0ae0a077 706 LoRaMacFlags.Bits.McpsReq = 1;
dudmuck 0:8f0d0ae0a077 707 }
dudmuck 0:8f0d0ae0a077 708 LoRaMacFlags.Bits.MacDone = 1;
dudmuck 0:8f0d0ae0a077 709 }
Wayne Roberts 29:ad409c68c0a6 710
Wayne Roberts 29:ad409c68c0a6 711 if (!LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 712 {
dudmuck 0:8f0d0ae0a077 713 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 714 ChannelsNbRepCounter++;
dudmuck 0:8f0d0ae0a077 715 }
Wayne Roberts 29:ad409c68c0a6 716
dudmuck 10:00997daeb0c0 717 MlmeIndication.MlmeIndication = MLME_TXDONE;
dudmuck 10:00997daeb0c0 718 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 719 LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
Wayne Roberts 29:ad409c68c0a6 720
Wayne Roberts 29:ad409c68c0a6 721 Radio::Standby( );
Wayne Roberts 29:ad409c68c0a6 722
Wayne Roberts 34:9c8966cd66a2 723 txDoneAt = Radio::irqAt /*+ lpt_offset*/;
dudmuck 16:915815632c1f 724 }
dudmuck 16:915815632c1f 725
dudmuck 16:915815632c1f 726
dudmuck 16:915815632c1f 727 static void application_callbacks()
dudmuck 16:915815632c1f 728 {
dudmuck 16:915815632c1f 729 if (LoRaMacFlags.Bits.McpsInd) {
dudmuck 16:915815632c1f 730 LoRaMacFlags.Bits.McpsInd = 0;
dudmuck 16:915815632c1f 731 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
dudmuck 16:915815632c1f 732 }
Wayne Roberts 29:ad409c68c0a6 733
dudmuck 16:915815632c1f 734 if (LoRaMacFlags.Bits.McpsReq) {
dudmuck 16:915815632c1f 735 LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm );
dudmuck 16:915815632c1f 736 LoRaMacFlags.Bits.McpsReq = 0;
Wayne Roberts 29:ad409c68c0a6 737 }
dudmuck 0:8f0d0ae0a077 738 }
dudmuck 0:8f0d0ae0a077 739
dudmuck 0:8f0d0ae0a077 740 static void PrepareRxDoneAbort( void )
dudmuck 0:8f0d0ae0a077 741 {
Wayne Roberts 29:ad409c68c0a6 742 if (LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 743 {
dudmuck 0:8f0d0ae0a077 744 OnAckTimeoutTimerEvent( );
dudmuck 0:8f0d0ae0a077 745 }
dudmuck 0:8f0d0ae0a077 746
dudmuck 0:8f0d0ae0a077 747 LoRaMacFlags.Bits.McpsInd = 1;
dudmuck 0:8f0d0ae0a077 748 LoRaMacFlags.Bits.MacDone = 1;
Wayne Roberts 29:ad409c68c0a6 749
dudmuck 16:915815632c1f 750 application_callbacks();
dudmuck 0:8f0d0ae0a077 751 }
dudmuck 0:8f0d0ae0a077 752
dudmuck 20:42839629a5dc 753 void send_bh()
Wayne Roberts 29:ad409c68c0a6 754 {
dudmuck 25:fed9d5b77183 755 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_SEND;
dudmuck 25:fed9d5b77183 756 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_SEND;
Wayne Roberts 29:ad409c68c0a6 757 McpsConfirm.TxPower = LoRaMacParams.ChannelsTxPower;
dudmuck 25:fed9d5b77183 758 McpsConfirm.UpLinkFrequency = Channels[Channel].Frequency;
dudmuck 25:fed9d5b77183 759
Wayne Roberts 29:ad409c68c0a6 760 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) // joining is channel hunting
Wayne Roberts 29:ad409c68c0a6 761 Radio::SetChannel( Channels[Channel].Frequency );
Wayne Roberts 29:ad409c68c0a6 762
Wayne Roberts 29:ad409c68c0a6 763 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
dudmuck 25:fed9d5b77183 764 {
dudmuck 25:fed9d5b77183 765 JoinRequestTrials++;
Wayne Roberts 29:ad409c68c0a6 766 mac_printf("join %luhz try%u DR%u\r\n", Channels[Channel].Frequency, JoinRequestTrials, LoRaMacParams.ChannelsDatarate_fixed);
dudmuck 25:fed9d5b77183 767 }
dudmuck 25:fed9d5b77183 768
Wayne Roberts 29:ad409c68c0a6 769 Radio::set_tx_dbm(TxPowers[LoRaMacParams.ChannelsTxPower]);
Wayne Roberts 29:ad409c68c0a6 770 Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, Datarates[LoRaMacParams.ChannelsDatarate_fixed], 1);
Wayne Roberts 29:ad409c68c0a6 771
Wayne Roberts 29:ad409c68c0a6 772 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 29:ad409c68c0a6 773 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false);
Wayne Roberts 29:ad409c68c0a6 774 Radio::Send(tx_buf_len, 0, 0, 0);
Wayne Roberts 29:ad409c68c0a6 775
dudmuck 25:fed9d5b77183 776 LoRaMacFlags.Bits.uplink_pending = 0; // sent
dudmuck 25:fed9d5b77183 777
dudmuck 25:fed9d5b77183 778 // Compute Rx1 windows parameters, taken at TxDone
Wayne Roberts 34:9c8966cd66a2 779 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) {
Wayne Roberts 34:9c8966cd66a2 780 microseconds us(LoRaMacParams.JoinAcceptDelay_us - TARGET_PRECESSION_us);
Wayne Roberts 34:9c8966cd66a2 781 RxWindowDelay_us = us - mcu_wakeup_latency;
Wayne Roberts 34:9c8966cd66a2 782 } else {
Wayne Roberts 34:9c8966cd66a2 783 microseconds us(LoRaMacParams.ReceiveDelay_us - TARGET_PRECESSION_us);
Wayne Roberts 34:9c8966cd66a2 784 RxWindowDelay_us = us - mcu_wakeup_latency;
Wayne Roberts 34:9c8966cd66a2 785 }
Wayne Roberts 29:ad409c68c0a6 786
Wayne Roberts 29:ad409c68c0a6 787 } // ..send_bh()
dudmuck 20:42839629a5dc 788
dudmuck 20:42839629a5dc 789 void send_callback()
Wayne Roberts 29:ad409c68c0a6 790 {
Wayne Roberts 34:9c8966cd66a2 791 LowPowerClock::time_point now = BeaconCtx.sendAt + BeaconCtx.lastSendAtErr;
Wayne Roberts 29:ad409c68c0a6 792
dudmuck 20:42839629a5dc 793 if (BeaconCtx.guard) {
dudmuck 25:fed9d5b77183 794 /* last send, this will be restarted after beacon sent */
dudmuck 20:42839629a5dc 795 return;
dudmuck 20:42839629a5dc 796 }
Wayne Roberts 29:ad409c68c0a6 797 BeaconCtx.sendOpportunities++;
Wayne Roberts 29:ad409c68c0a6 798
Wayne Roberts 34:9c8966cd66a2 799 microseconds ping_slot_us(BeaconCtx.periodicity_slots * PING_SLOT_RESOLUTION_us);
Wayne Roberts 34:9c8966cd66a2 800 BeaconCtx.sendAt += ping_slot_us;
Wayne Roberts 29:ad409c68c0a6 801 if (BeaconCtx.state == BEACON_STATE_LOCKED) {
Wayne Roberts 34:9c8966cd66a2 802 float sinceBeacon = now.time_since_epoch().count() - BeaconCtx.LastBeaconRxAt.time_since_epoch().count();
Wayne Roberts 29:ad409c68c0a6 803 float ratio = sinceBeacon / BEACON_INTERVAL_us;
Wayne Roberts 34:9c8966cd66a2 804 microseconds duration_err_us((int)(BeaconCtx.last_BeaconRxTimerError_us * ratio));
Wayne Roberts 34:9c8966cd66a2 805 tx_timeout.attach_absolute(&send_callback, BeaconCtx.sendAt + duration_err_us - mcu_wakeup_latency);
Wayne Roberts 34:9c8966cd66a2 806 BeaconCtx.lastSendAtErr = duration_err_us;
Wayne Roberts 34:9c8966cd66a2 807 } else {
Wayne Roberts 34:9c8966cd66a2 808 microseconds duration_err_us(0);
Wayne Roberts 34:9c8966cd66a2 809 tx_timeout.attach_absolute(&send_callback, BeaconCtx.sendAt - mcu_wakeup_latency);
Wayne Roberts 34:9c8966cd66a2 810 BeaconCtx.lastSendAtErr = duration_err_us;
Wayne Roberts 29:ad409c68c0a6 811 }
Wayne Roberts 29:ad409c68c0a6 812
Wayne Roberts 30:1c35c4f56e50 813 if (LoRaMacFlags.Bits.uplink_pending) {
Wayne Roberts 34:9c8966cd66a2 814 us_timestamp_t untilGuard = (BeaconCtx.rx_setup_at.time_since_epoch().count() - BEACON_GUARD_us) - LowPowerClock::now().time_since_epoch().count();
Wayne Roberts 30:1c35c4f56e50 815 if (untilGuard > (RECEIVE_DELAY_us + TARGET_PRECESSION_us))
Wayne Roberts 30:1c35c4f56e50 816 LoRaMacFlags.Bits.send = 1;
Wayne Roberts 30:1c35c4f56e50 817 }
dudmuck 0:8f0d0ae0a077 818 }
dudmuck 0:8f0d0ae0a077 819
dudmuck 0:8f0d0ae0a077 820 void OnRxBeaconSetup()
dudmuck 0:8f0d0ae0a077 821 {
Wayne Roberts 30:1c35c4f56e50 822 BeaconCtx.guard = false;
Wayne Roberts 29:ad409c68c0a6 823 LoRaMacFlags.Bits.expecting_beacon = true;
Wayne Roberts 29:ad409c68c0a6 824
Wayne Roberts 29:ad409c68c0a6 825 Radio::Rx(2000);
Wayne Roberts 29:ad409c68c0a6 826
Wayne Roberts 34:9c8966cd66a2 827 BeaconCtx.lastSendAtErr = microseconds(0);
dudmuck 16:915815632c1f 828 }
dudmuck 16:915815632c1f 829
dudmuck 16:915815632c1f 830 void guard_callback()
dudmuck 16:915815632c1f 831 {
dudmuck 16:915815632c1f 832 BeaconCtx.guard = true;
Wayne Roberts 30:1c35c4f56e50 833 Radio::Standby( );
Wayne Roberts 30:1c35c4f56e50 834 Radio::SetChannel( Channels[Channel].Frequency );
dudmuck 21:500ff43d8424 835
Wayne Roberts 34:9c8966cd66a2 836 tx_timeout.detach();
Wayne Roberts 29:ad409c68c0a6 837 mac_printf("sendOpportunities:%u\r\n", BeaconCtx.sendOpportunities);
Wayne Roberts 29:ad409c68c0a6 838 BeaconCtx.sendOpportunities = 0;
Wayne Roberts 30:1c35c4f56e50 839
Wayne Roberts 30:1c35c4f56e50 840 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 30:1c35c4f56e50 841 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, true, false, false);
Wayne Roberts 30:1c35c4f56e50 842 Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, Datarates[BEACON_CHANNEL_DR], 1);
Wayne Roberts 30:1c35c4f56e50 843 Radio::SetFixedPayloadLength(BEACON_SIZE);
Wayne Roberts 30:1c35c4f56e50 844
Wayne Roberts 30:1c35c4f56e50 845 #ifdef SX128x_H
Wayne Roberts 30:1c35c4f56e50 846 /* explicit to implicit header: does sx1280 really need this a 2nd time? */
Wayne Roberts 30:1c35c4f56e50 847 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 30:1c35c4f56e50 848 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, true, false, false);
Wayne Roberts 30:1c35c4f56e50 849 #endif /* SX128x_H */
Wayne Roberts 30:1c35c4f56e50 850 Radio::SetLoRaSymbolTimeout(BeaconCtx.nSymbsTimeout);
dudmuck 0:8f0d0ae0a077 851 }
dudmuck 0:8f0d0ae0a077 852
Wayne Roberts 29:ad409c68c0a6 853 static void us_to_nSymbTimeout(unsigned us)
dudmuck 0:8f0d0ae0a077 854 {
Wayne Roberts 29:ad409c68c0a6 855 mac_printf("symTo:%u ", us);
Wayne Roberts 29:ad409c68c0a6 856 BeaconCtx.nSymbsTimeout = us / BeaconCtx.symbol_period_us;
Wayne Roberts 29:ad409c68c0a6 857 if (BeaconCtx.nSymbsTimeout < (MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols)) {
Wayne Roberts 29:ad409c68c0a6 858 BeaconCtx.nSymbsTimeout = MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols;
Wayne Roberts 29:ad409c68c0a6 859 } else if (BeaconCtx.nSymbsTimeout > 255)
Wayne Roberts 29:ad409c68c0a6 860 BeaconCtx.nSymbsTimeout = 255;
Wayne Roberts 29:ad409c68c0a6 861
Wayne Roberts 29:ad409c68c0a6 862 BeaconCtx.SymbolTimeout_us = BeaconCtx.nSymbsTimeout * BeaconCtx.symbol_period_us;
Wayne Roberts 29:ad409c68c0a6 863 mac_printf("%u\r\n", BeaconCtx.nSymbsTimeout);
dudmuck 0:8f0d0ae0a077 864 }
dudmuck 0:8f0d0ae0a077 865
dudmuck 0:8f0d0ae0a077 866 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
dudmuck 0:8f0d0ae0a077 867 {
dudmuck 0:8f0d0ae0a077 868 // The CRC calculation follows CCITT
dudmuck 0:8f0d0ae0a077 869 const uint16_t polynom = 0x1021;
dudmuck 0:8f0d0ae0a077 870 // CRC initial value
dudmuck 0:8f0d0ae0a077 871 uint16_t crc = 0x0000;
dudmuck 0:8f0d0ae0a077 872
dudmuck 0:8f0d0ae0a077 873 if( buffer == NULL )
dudmuck 0:8f0d0ae0a077 874 {
dudmuck 0:8f0d0ae0a077 875 return 0;
dudmuck 0:8f0d0ae0a077 876 }
dudmuck 0:8f0d0ae0a077 877
dudmuck 0:8f0d0ae0a077 878 for( uint16_t i = 0; i < length; ++i )
dudmuck 0:8f0d0ae0a077 879 {
dudmuck 0:8f0d0ae0a077 880 crc ^= ( uint16_t ) buffer[i] << 8;
dudmuck 0:8f0d0ae0a077 881 for( uint16_t j = 0; j < 8; ++j )
dudmuck 0:8f0d0ae0a077 882 {
dudmuck 0:8f0d0ae0a077 883 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
dudmuck 0:8f0d0ae0a077 884 }
dudmuck 0:8f0d0ae0a077 885 }
dudmuck 0:8f0d0ae0a077 886
dudmuck 0:8f0d0ae0a077 887 return crc;
dudmuck 0:8f0d0ae0a077 888 }
dudmuck 0:8f0d0ae0a077 889
Wayne Roberts 29:ad409c68c0a6 890 void rx_beacon(uint16_t size)
dudmuck 0:8f0d0ae0a077 891 {
dudmuck 0:8f0d0ae0a077 892 static bool compensate_precession = false;
dudmuck 0:8f0d0ae0a077 893 int32_t compensation = 0;
Wayne Roberts 34:9c8966cd66a2 894 /* have beacon end, need beacon start */
Wayne Roberts 34:9c8966cd66a2 895 microseconds beacon_start_offset_us(BeaconCtx.beaconStartToRxDone);
Wayne Roberts 34:9c8966cd66a2 896 LowPowerClock::time_point ThisBeaconRxAt = Radio::irqAt - beacon_start_offset_us;
Wayne Roberts 29:ad409c68c0a6 897
Wayne Roberts 30:1c35c4f56e50 898 BeaconCtx.num_consecutive_ok++;
Wayne Roberts 34:9c8966cd66a2 899 mac_printf("rx_beacon %llu ", Radio::irqAt.time_since_epoch().count());
Wayne Roberts 34:9c8966cd66a2 900 BeaconCtx.rx_precession_us = ThisBeaconRxAt.time_since_epoch().count() - BeaconCtx.rx_setup_at.time_since_epoch().count();
dudmuck 0:8f0d0ae0a077 901 if (BeaconCtx.state != BEACON_STATE_FIRST_ACQ) {
dudmuck 13:18de9ee3a461 902 BeaconCtx.known_working_BeaconRxTimerError_us = BeaconCtx.last_BeaconRxTimerError_us;
Wayne Roberts 34:9c8966cd66a2 903 BeaconCtx.last_BeaconRxTimerError_us = (ThisBeaconRxAt.time_since_epoch().count() - BeaconCtx.LastBeaconRxAt.time_since_epoch().count()) - (BEACON_INTERVAL_us * (BeaconCtx.num_missed+1));
Wayne Roberts 29:ad409c68c0a6 904
Wayne Roberts 29:ad409c68c0a6 905 if (BeaconCtx.num_missed > 0) {
Wayne Roberts 29:ad409c68c0a6 906 /* Timer error is measured over more than one beacon period.
Wayne Roberts 29:ad409c68c0a6 907 * Scale to error seen over single beacon period */
Wayne Roberts 29:ad409c68c0a6 908 BeaconCtx.last_BeaconRxTimerError_us /= BeaconCtx.num_missed + 1;
dudmuck 0:8f0d0ae0a077 909 }
dudmuck 0:8f0d0ae0a077 910
dudmuck 0:8f0d0ae0a077 911 if (BeaconCtx.state == BEACON_STATE_ACQ_ERROR) {
Wayne Roberts 29:ad409c68c0a6 912 mac_printf("-->LOCKED ");
dudmuck 21:500ff43d8424 913 BeaconCtx.state = BEACON_STATE_LOCKED;
dudmuck 0:8f0d0ae0a077 914 compensate_precession = true;
dudmuck 0:8f0d0ae0a077 915 }
dudmuck 0:8f0d0ae0a077 916 } else {
dudmuck 0:8f0d0ae0a077 917 /* ignore precession at first acquisition because it has slot resolution added */
Wayne Roberts 29:ad409c68c0a6 918 mac_printf("-->ACQ_ERROR ");
dudmuck 0:8f0d0ae0a077 919 // next beacon will give us our crystal error
dudmuck 0:8f0d0ae0a077 920 BeaconCtx.state = BEACON_STATE_ACQ_ERROR;
dudmuck 0:8f0d0ae0a077 921 }
dudmuck 0:8f0d0ae0a077 922
Wayne Roberts 34:9c8966cd66a2 923 mac_printf("err%d=%llu-%llu ", BeaconCtx.last_BeaconRxTimerError_us, ThisBeaconRxAt.time_since_epoch().count(), BeaconCtx.LastBeaconRxAt.time_since_epoch().count());
Wayne Roberts 29:ad409c68c0a6 924 if (BeaconCtx.num_missed > 0)
Wayne Roberts 29:ad409c68c0a6 925 mac_printf("missed%u ", BeaconCtx.num_missed);
Wayne Roberts 29:ad409c68c0a6 926
Wayne Roberts 29:ad409c68c0a6 927 mac_printf(" rx-before-tx:%d ", BeaconCtx.rx_precession_us);
Wayne Roberts 29:ad409c68c0a6 928 if (BeaconCtx.last_BeaconRxTimerError_us > 40000 || BeaconCtx.last_BeaconRxTimerError_us < -40000) {
Wayne Roberts 34:9c8966cd66a2 929 BeaconCtx.timeout_rx.detach();
Wayne Roberts 34:9c8966cd66a2 930 BeaconCtx.timeout_guard.detach();
Wayne Roberts 29:ad409c68c0a6 931 mac_printf("halt\r\n");
Wayne Roberts 29:ad409c68c0a6 932 for (;;) asm("nop");
Wayne Roberts 29:ad409c68c0a6 933 }
Wayne Roberts 34:9c8966cd66a2 934 BeaconCtx.LastBeaconRxAt = ThisBeaconRxAt;
dudmuck 0:8f0d0ae0a077 935
dudmuck 21:500ff43d8424 936 if (BeaconCtx.state == BEACON_STATE_LOCKED) {
dudmuck 0:8f0d0ae0a077 937 if (compensate_precession) {
Wayne Roberts 29:ad409c68c0a6 938 compensation = BeaconCtx.rx_precession_us - TARGET_PRECESSION_us + BeaconCtx.last_BeaconRxTimerError_us;
Wayne Roberts 29:ad409c68c0a6 939 mac_printf(" comp%ld", compensation);
dudmuck 0:8f0d0ae0a077 940 }
dudmuck 0:8f0d0ae0a077 941 }
dudmuck 0:8f0d0ae0a077 942
Wayne Roberts 29:ad409c68c0a6 943 // reference tick for uplink schedule: when gateway started beacon
Wayne Roberts 34:9c8966cd66a2 944 microseconds send_offset_us(BeaconCtx.rx_precession_us + (BeaconCtx.tx_slot_offset * PING_SLOT_RESOLUTION_us));
Wayne Roberts 34:9c8966cd66a2 945 BeaconCtx.sendAt = BeaconCtx.rx_setup_at + send_offset_us;
Wayne Roberts 34:9c8966cd66a2 946 tx_timeout.attach_absolute(&send_callback, BeaconCtx.sendAt - mcu_wakeup_latency);
Wayne Roberts 34:9c8966cd66a2 947 mac_printf("sendAt:%llu ", BeaconCtx.sendAt.time_since_epoch().count());
Wayne Roberts 34:9c8966cd66a2 948
Wayne Roberts 34:9c8966cd66a2 949 microseconds us_to_next_beacon(BEACON_INTERVAL_us + compensation);
Wayne Roberts 34:9c8966cd66a2 950 BeaconCtx.rx_setup_at += us_to_next_beacon;
Wayne Roberts 34:9c8966cd66a2 951
Wayne Roberts 34:9c8966cd66a2 952 BeaconCtx.timeout_rx.attach_absolute(&OnRxBeaconSetup, BeaconCtx.rx_setup_at - mcu_wakeup_latency);
Wayne Roberts 34:9c8966cd66a2 953 microseconds beacon_guard_us(BEACON_GUARD_us);
Wayne Roberts 34:9c8966cd66a2 954 BeaconCtx.timeout_guard.attach_absolute(&guard_callback, BeaconCtx.rx_setup_at - beacon_guard_us - mcu_wakeup_latency);
dudmuck 0:8f0d0ae0a077 955
dudmuck 0:8f0d0ae0a077 956 BeaconCtx.num_missed = 0;
dudmuck 0:8f0d0ae0a077 957
dudmuck 0:8f0d0ae0a077 958 MlmeIndication.MlmeIndication = MLME_BEACON;
dudmuck 0:8f0d0ae0a077 959 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED;
dudmuck 0:8f0d0ae0a077 960 LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
dudmuck 0:8f0d0ae0a077 961
dudmuck 0:8f0d0ae0a077 962 /* check beacon payload */
Wayne Roberts 29:ad409c68c0a6 963 uint16_t calc_crc = beacon_crc(Radio::radio.rx_buf, 4);
Wayne Roberts 29:ad409c68c0a6 964 uint16_t rx_crc = Radio::radio.rx_buf[4];
Wayne Roberts 29:ad409c68c0a6 965 rx_crc |= Radio::radio.rx_buf[5] << 8;
dudmuck 0:8f0d0ae0a077 966 if (rx_crc == calc_crc) {
Wayne Roberts 29:ad409c68c0a6 967 unsigned int rx = Radio::radio.rx_buf[0];
Wayne Roberts 29:ad409c68c0a6 968 rx |= Radio::radio.rx_buf[1] << 8;
Wayne Roberts 29:ad409c68c0a6 969 rx |= Radio::radio.rx_buf[2] << 16;
Wayne Roberts 29:ad409c68c0a6 970 rx |= Radio::radio.rx_buf[3] << 24;
dudmuck 10:00997daeb0c0 971 if (rx != 0) {
dudmuck 10:00997daeb0c0 972 McpsIndication.McpsIndication = MCPS_MULTICAST;
dudmuck 10:00997daeb0c0 973 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 974 McpsIndication.Buffer = Radio::radio.rx_buf;
dudmuck 10:00997daeb0c0 975 McpsIndication.BufferSize = 4;
dudmuck 10:00997daeb0c0 976 McpsIndication.RxData = true;
dudmuck 16:915815632c1f 977 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
dudmuck 10:00997daeb0c0 978 }
dudmuck 0:8f0d0ae0a077 979 } else
Wayne Roberts 29:ad409c68c0a6 980 mac_printf("calc_crc:%04x rx_crc:%04x\r\n", calc_crc, rx_crc);
Wayne Roberts 29:ad409c68c0a6 981 } // ..rx_beacon()
Wayne Roberts 29:ad409c68c0a6 982
Wayne Roberts 29:ad409c68c0a6 983
Wayne Roberts 29:ad409c68c0a6 984 #define JOIN_ACCEPT_MAX_SIZE 34
Wayne Roberts 29:ad409c68c0a6 985 static void OnRadioRxDone(uint8_t size, float rssi, float snr )
dudmuck 0:8f0d0ae0a077 986 {
Wayne Roberts 29:ad409c68c0a6 987 uint8_t _jaDecrypted[JOIN_ACCEPT_MAX_SIZE];
dudmuck 0:8f0d0ae0a077 988 LoRaMacHeader_t macHdr;
dudmuck 0:8f0d0ae0a077 989 LoRaMacFrameCtrl_t fCtrl;
dudmuck 0:8f0d0ae0a077 990 bool skipIndication = false;
dudmuck 0:8f0d0ae0a077 991
dudmuck 0:8f0d0ae0a077 992 uint8_t pktHeaderLen = 0;
dudmuck 0:8f0d0ae0a077 993 uint32_t address = 0;
dudmuck 0:8f0d0ae0a077 994 uint8_t appPayloadStartIndex = 0;
dudmuck 0:8f0d0ae0a077 995 uint8_t port = 0xFF;
dudmuck 0:8f0d0ae0a077 996 uint8_t frameLen = 0;
dudmuck 0:8f0d0ae0a077 997 uint32_t mic = 0;
dudmuck 0:8f0d0ae0a077 998 uint32_t micRx = 0;
dudmuck 0:8f0d0ae0a077 999
dudmuck 0:8f0d0ae0a077 1000 uint16_t sequenceCounter = 0;
dudmuck 0:8f0d0ae0a077 1001 uint16_t sequenceCounterPrev = 0;
dudmuck 0:8f0d0ae0a077 1002 uint16_t sequenceCounterDiff = 0;
dudmuck 0:8f0d0ae0a077 1003 uint32_t downLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1004
dudmuck 0:8f0d0ae0a077 1005 MulticastParams_t *curMulticastParams = NULL;
dudmuck 0:8f0d0ae0a077 1006 uint8_t *nwkSKey = LoRaMacNwkSKey;
dudmuck 0:8f0d0ae0a077 1007 uint8_t *appSKey = LoRaMacAppSKey;
dudmuck 0:8f0d0ae0a077 1008
dudmuck 0:8f0d0ae0a077 1009 uint8_t multicast = 0;
dudmuck 0:8f0d0ae0a077 1010
dudmuck 0:8f0d0ae0a077 1011 bool isMicOk = false;
dudmuck 0:8f0d0ae0a077 1012
dudmuck 0:8f0d0ae0a077 1013 McpsConfirm.AckReceived = false;
dudmuck 0:8f0d0ae0a077 1014 McpsIndication.Rssi = rssi;
dudmuck 0:8f0d0ae0a077 1015 McpsIndication.Snr = snr;
dudmuck 0:8f0d0ae0a077 1016 McpsIndication.Port = 0;
dudmuck 0:8f0d0ae0a077 1017 McpsIndication.Multicast = 0;
dudmuck 0:8f0d0ae0a077 1018 McpsIndication.FramePending = 0;
dudmuck 0:8f0d0ae0a077 1019 McpsIndication.Buffer = NULL;
dudmuck 0:8f0d0ae0a077 1020 McpsIndication.BufferSize = 0;
dudmuck 0:8f0d0ae0a077 1021 McpsIndication.RxData = false;
dudmuck 0:8f0d0ae0a077 1022 McpsIndication.AckReceived = false;
dudmuck 0:8f0d0ae0a077 1023 McpsIndication.DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1024 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
dudmuck 0:8f0d0ae0a077 1025
Wayne Roberts 29:ad409c68c0a6 1026 Radio::Sleep( );
Wayne Roberts 29:ad409c68c0a6 1027
Wayne Roberts 29:ad409c68c0a6 1028 if (LoRaMacFlags.Bits.expecting_beacon) {
Wayne Roberts 29:ad409c68c0a6 1029 rx_beacon(size);
Wayne Roberts 29:ad409c68c0a6 1030 LoRaMacFlags.Bits.expecting_beacon = false;
dudmuck 0:8f0d0ae0a077 1031 return;
dudmuck 0:8f0d0ae0a077 1032 }
dudmuck 0:8f0d0ae0a077 1033
Wayne Roberts 29:ad409c68c0a6 1034 macHdr.Value = Radio::radio.rx_buf[pktHeaderLen++];
dudmuck 0:8f0d0ae0a077 1035
dudmuck 0:8f0d0ae0a077 1036 switch( macHdr.Bits.MType )
dudmuck 0:8f0d0ae0a077 1037 {
dudmuck 0:8f0d0ae0a077 1038 case FRAME_TYPE_JOIN_ACCEPT:
Wayne Roberts 29:ad409c68c0a6 1039 if (LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
dudmuck 0:8f0d0ae0a077 1040 {
dudmuck 2:f2d9aa163652 1041 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_JOIN_ACCEPT;
dudmuck 0:8f0d0ae0a077 1042 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1043 return;
dudmuck 0:8f0d0ae0a077 1044 }
Wayne Roberts 29:ad409c68c0a6 1045 LoRaMacJoinDecrypt( Radio::radio.rx_buf + 1, size - 1, LoRaMacAppKey, &_jaDecrypted[1]);
Wayne Roberts 29:ad409c68c0a6 1046
Wayne Roberts 29:ad409c68c0a6 1047 _jaDecrypted[0] = macHdr.Value;
Wayne Roberts 29:ad409c68c0a6 1048
Wayne Roberts 29:ad409c68c0a6 1049 LoRaMacJoinComputeMic( _jaDecrypted, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic );
Wayne Roberts 29:ad409c68c0a6 1050
Wayne Roberts 29:ad409c68c0a6 1051 micRx |= ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN];
Wayne Roberts 29:ad409c68c0a6 1052 micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 1] << 8 );
Wayne Roberts 29:ad409c68c0a6 1053 micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 2] << 16 );
Wayne Roberts 29:ad409c68c0a6 1054 micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 3] << 24 );
dudmuck 0:8f0d0ae0a077 1055
dudmuck 0:8f0d0ae0a077 1056 if( micRx == mic )
dudmuck 0:8f0d0ae0a077 1057 {
Wayne Roberts 30:1c35c4f56e50 1058 uint32_t beaconDur;
Wayne Roberts 29:ad409c68c0a6 1059 LoRaMacJoinComputeSKeys( LoRaMacAppKey, _jaDecrypted + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
Wayne Roberts 29:ad409c68c0a6 1060
Wayne Roberts 29:ad409c68c0a6 1061 LoRaMacNetID = ( uint32_t )_jaDecrypted[4];
Wayne Roberts 29:ad409c68c0a6 1062 LoRaMacNetID |= ( ( uint32_t )_jaDecrypted[5] << 8 );
Wayne Roberts 29:ad409c68c0a6 1063 LoRaMacNetID |= ( ( uint32_t )_jaDecrypted[6] << 16 );
Wayne Roberts 29:ad409c68c0a6 1064
Wayne Roberts 29:ad409c68c0a6 1065 LoRaMacDevAddr = ( uint32_t )_jaDecrypted[7];
Wayne Roberts 29:ad409c68c0a6 1066 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[8] << 8 );
Wayne Roberts 29:ad409c68c0a6 1067 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[9] << 16 );
Wayne Roberts 29:ad409c68c0a6 1068 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[10] << 24 );
dudmuck 0:8f0d0ae0a077 1069
dudmuck 0:8f0d0ae0a077 1070 // DLSettings
Wayne Roberts 29:ad409c68c0a6 1071 LoRaMacParams.Rx1DrOffset = ( _jaDecrypted[11] >> 4 ) & 0x07;
Wayne Roberts 29:ad409c68c0a6 1072
Wayne Roberts 29:ad409c68c0a6 1073 LoRaMacParams.ReceiveDelay_us = ( _jaDecrypted[12] & 0x0F );
dudmuck 0:8f0d0ae0a077 1074 if( LoRaMacParams.ReceiveDelay_us == 0 )
dudmuck 0:8f0d0ae0a077 1075 LoRaMacParams.ReceiveDelay_us = RECEIVE_DELAY_us;
dudmuck 0:8f0d0ae0a077 1076 else
dudmuck 0:8f0d0ae0a077 1077 LoRaMacParams.ReceiveDelay_us *= 10;
dudmuck 0:8f0d0ae0a077 1078
Wayne Roberts 29:ad409c68c0a6 1079 uint16_t beaconTimingDelay = _jaDecrypted[13] & 0xff;
Wayne Roberts 29:ad409c68c0a6 1080 beaconTimingDelay |= _jaDecrypted[14] << 8;
Wayne Roberts 29:ad409c68c0a6 1081
Wayne Roberts 29:ad409c68c0a6 1082 mac_printf("%lx slots:%x (rxdelay %lu)", LoRaMacDevAddr, beaconTimingDelay, LoRaMacParams.ReceiveDelay_us);
Wayne Roberts 29:ad409c68c0a6 1083 {
Wayne Roberts 29:ad409c68c0a6 1084 unsigned us_to_beacon = ( PING_SLOT_RESOLUTION_us * beaconTimingDelay );
Wayne Roberts 29:ad409c68c0a6 1085 mac_printf(" us_to_beacon:%u ", us_to_beacon);
Wayne Roberts 29:ad409c68c0a6 1086 // time to beacon given as referenced to end of join request uplink
Wayne Roberts 34:9c8966cd66a2 1087 microseconds tx_done_to_rx_start_us(us_to_beacon - PPM_BEACON_INTERVAL);
Wayne Roberts 34:9c8966cd66a2 1088 BeaconCtx.rx_setup_at = txDoneAt + tx_done_to_rx_start_us;
Wayne Roberts 34:9c8966cd66a2 1089 BeaconCtx.timeout_rx.attach_absolute(&OnRxBeaconSetup, BeaconCtx.rx_setup_at - mcu_wakeup_latency);
Wayne Roberts 34:9c8966cd66a2 1090 microseconds beacon_guard_us(BEACON_GUARD_us);
Wayne Roberts 34:9c8966cd66a2 1091 BeaconCtx.timeout_guard.attach_absolute(&guard_callback, BeaconCtx.rx_setup_at - (beacon_guard_us + mcu_wakeup_latency));
Wayne Roberts 34:9c8966cd66a2 1092
Wayne Roberts 34:9c8966cd66a2 1093 mac_printf("beaconIn:%llu\r\n", BeaconCtx.rx_setup_at.time_since_epoch().count() - LowPowerClock::now().time_since_epoch().count());
Wayne Roberts 29:ad409c68c0a6 1094 }
Wayne Roberts 29:ad409c68c0a6 1095
Wayne Roberts 29:ad409c68c0a6 1096 BeaconCtx.tx_slot_offset = _jaDecrypted[15];
Wayne Roberts 29:ad409c68c0a6 1097 BeaconCtx.tx_slot_offset |= _jaDecrypted[16] << 8;
Wayne Roberts 29:ad409c68c0a6 1098 BeaconCtx.periodicity_slots = _jaDecrypted[17];
Wayne Roberts 29:ad409c68c0a6 1099 BeaconCtx.periodicity_slots |= _jaDecrypted[18] << 8;
Wayne Roberts 29:ad409c68c0a6 1100
Wayne Roberts 30:1c35c4f56e50 1101 beaconDur = _jaDecrypted[22];
Wayne Roberts 30:1c35c4f56e50 1102 beaconDur <<= 8;
Wayne Roberts 30:1c35c4f56e50 1103 beaconDur |= _jaDecrypted[21];
Wayne Roberts 30:1c35c4f56e50 1104 beaconDur <<= 8;
Wayne Roberts 30:1c35c4f56e50 1105 beaconDur |= _jaDecrypted[20];
Wayne Roberts 30:1c35c4f56e50 1106 beaconDur <<= 8;
Wayne Roberts 30:1c35c4f56e50 1107 beaconDur |= _jaDecrypted[19];
Wayne Roberts 30:1c35c4f56e50 1108 BeaconCtx.beaconStartToRxDone = beaconDur + (rxLatencyFactorFromSF[SF_FROM_DR_(LORAMAC_DEFAULT_DATARATE)-FASTEST_SF] * BeaconCtx.symbol_period_us);
Wayne Roberts 30:1c35c4f56e50 1109
Wayne Roberts 30:1c35c4f56e50 1110
Wayne Roberts 29:ad409c68c0a6 1111 /* nowSlot: now vs previous beacon */
Wayne Roberts 34:9c8966cd66a2 1112 microseconds beacon_interval_us(BEACON_INTERVAL_us);
Wayne Roberts 34:9c8966cd66a2 1113 BeaconCtx.LastBeaconRxAt = BeaconCtx.rx_setup_at - beacon_interval_us;
Wayne Roberts 34:9c8966cd66a2 1114 unsigned us_since_last_beacon = LowPowerClock::now().time_since_epoch().count() - BeaconCtx.LastBeaconRxAt.time_since_epoch().count();
Wayne Roberts 29:ad409c68c0a6 1115 unsigned nowSlot = us_since_last_beacon / PING_SLOT_RESOLUTION_us;
Wayne Roberts 29:ad409c68c0a6 1116 unsigned useSlot = BeaconCtx.tx_slot_offset;
Wayne Roberts 29:ad409c68c0a6 1117 while (useSlot < nowSlot)
Wayne Roberts 29:ad409c68c0a6 1118 useSlot += BeaconCtx.periodicity_slots;
Wayne Roberts 29:ad409c68c0a6 1119
Wayne Roberts 34:9c8966cd66a2 1120 mac_printf("beaconDur:0x%lx (%lu) useSlot:%u nowSlot:%u ", beaconDur, BeaconCtx.beaconStartToRxDone, useSlot, nowSlot);
Wayne Roberts 34:9c8966cd66a2 1121 microseconds ping_slot_offset_us(useSlot * PING_SLOT_RESOLUTION_us);
Wayne Roberts 34:9c8966cd66a2 1122 BeaconCtx.sendAt = BeaconCtx.LastBeaconRxAt + ping_slot_offset_us;
Wayne Roberts 34:9c8966cd66a2 1123
Wayne Roberts 34:9c8966cd66a2 1124 mac_printf("sendIn:%lld\r\n", BeaconCtx.sendAt.time_since_epoch().count() - LowPowerClock::now().time_since_epoch().count());
Wayne Roberts 34:9c8966cd66a2 1125 tx_timeout.attach_absolute(send_callback, BeaconCtx.sendAt - mcu_wakeup_latency);
Wayne Roberts 29:ad409c68c0a6 1126 BeaconCtx.sendOpportunities = 0;
Wayne Roberts 29:ad409c68c0a6 1127
dudmuck 0:8f0d0ae0a077 1128 BeaconCtx.state = BEACON_STATE_FIRST_ACQ;
dudmuck 16:915815632c1f 1129 BeaconCtx.guard = false;
dudmuck 0:8f0d0ae0a077 1130 BeaconCtx.num_missed = 0;
dudmuck 0:8f0d0ae0a077 1131 BeaconCtx.rx_precession_us = 0;
Wayne Roberts 30:1c35c4f56e50 1132 BeaconCtx.num_consecutive_ok = 0;
Wayne Roberts 29:ad409c68c0a6 1133 BeaconCtx.last_BeaconRxTimerError_us = -PPM_BEACON_INTERVAL;
Wayne Roberts 29:ad409c68c0a6 1134 BeaconCtx.known_working_BeaconRxTimerError_us = -PPM_BEACON_INTERVAL;
Wayne Roberts 29:ad409c68c0a6 1135 /* first beacon reception needs to open for 30ms timing resolution */
dudmuck 32:ac904adfc842 1136 BeaconCtx.Precess_symbols = ceil((float)(TARGET_PRECESSION_us / BeaconCtx.symbol_period_us));
Wayne Roberts 30:1c35c4f56e50 1137 BeaconCtx.SymbolTimeout_us = PING_SLOT_RESOLUTION_us + (PPM_BEACON_INTERVAL * 4); // error unknown at start
Wayne Roberts 29:ad409c68c0a6 1138 BeaconCtx.nSymbsTimeout = BeaconCtx.SymbolTimeout_us / BeaconCtx.symbol_period_us;
Wayne Roberts 29:ad409c68c0a6 1139 if (BeaconCtx.nSymbsTimeout < MIN_SYMBOL_TIMEOUT)
Wayne Roberts 29:ad409c68c0a6 1140 BeaconCtx.nSymbsTimeout = MIN_SYMBOL_TIMEOUT;
Wayne Roberts 29:ad409c68c0a6 1141 else if (BeaconCtx.nSymbsTimeout > 255)
Wayne Roberts 29:ad409c68c0a6 1142 BeaconCtx.nSymbsTimeout = 255;
Wayne Roberts 29:ad409c68c0a6 1143 mac_printf("startSymbTo:%u ", BeaconCtx.nSymbsTimeout);
dudmuck 0:8f0d0ae0a077 1144
dudmuck 0:8f0d0ae0a077 1145 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 1146 LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = true;
dudmuck 0:8f0d0ae0a077 1147 LoRaMacParams.ChannelsDatarate_fixed = LoRaMacParamsDefaults.ChannelsDatarate_fixed;
dudmuck 0:8f0d0ae0a077 1148 }
dudmuck 0:8f0d0ae0a077 1149 else
dudmuck 0:8f0d0ae0a077 1150 {
dudmuck 0:8f0d0ae0a077 1151 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
Wayne Roberts 30:1c35c4f56e50 1152 mac_printf("join-mic-fail size:%u\r\n", size);
dudmuck 0:8f0d0ae0a077 1153 JoinRequestTrials = MaxJoinRequestTrials; // stop trying
dudmuck 0:8f0d0ae0a077 1154 }
dudmuck 16:915815632c1f 1155 LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
dudmuck 16:915815632c1f 1156 LoRaMacFlags.Bits.MlmeReq = 0; // MacMlmeConfirm() called
dudmuck 0:8f0d0ae0a077 1157 break;
dudmuck 0:8f0d0ae0a077 1158 case FRAME_TYPE_DATA_CONFIRMED_DOWN:
dudmuck 0:8f0d0ae0a077 1159 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
dudmuck 0:8f0d0ae0a077 1160 {
Wayne Roberts 29:ad409c68c0a6 1161 address = Radio::radio.rx_buf[pktHeaderLen++];
Wayne Roberts 29:ad409c68c0a6 1162 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 8 );
Wayne Roberts 29:ad409c68c0a6 1163 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 16 );
Wayne Roberts 29:ad409c68c0a6 1164 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 24 );
dudmuck 0:8f0d0ae0a077 1165
dudmuck 0:8f0d0ae0a077 1166 if( address != LoRaMacDevAddr )
dudmuck 0:8f0d0ae0a077 1167 {
dudmuck 0:8f0d0ae0a077 1168 curMulticastParams = MulticastChannels;
dudmuck 0:8f0d0ae0a077 1169 while( curMulticastParams != NULL )
dudmuck 0:8f0d0ae0a077 1170 {
dudmuck 0:8f0d0ae0a077 1171 if( address == curMulticastParams->Address )
dudmuck 0:8f0d0ae0a077 1172 {
dudmuck 0:8f0d0ae0a077 1173 multicast = 1;
dudmuck 0:8f0d0ae0a077 1174 nwkSKey = curMulticastParams->NwkSKey;
dudmuck 0:8f0d0ae0a077 1175 appSKey = curMulticastParams->AppSKey;
dudmuck 0:8f0d0ae0a077 1176 downLinkCounter = curMulticastParams->DownLinkCounter;
dudmuck 0:8f0d0ae0a077 1177 break;
dudmuck 0:8f0d0ae0a077 1178 }
dudmuck 0:8f0d0ae0a077 1179 curMulticastParams = curMulticastParams->Next;
dudmuck 0:8f0d0ae0a077 1180 }
dudmuck 0:8f0d0ae0a077 1181 if( multicast == 0 )
dudmuck 0:8f0d0ae0a077 1182 {
dudmuck 0:8f0d0ae0a077 1183 // We are not the destination of this frame.
dudmuck 0:8f0d0ae0a077 1184 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
dudmuck 0:8f0d0ae0a077 1185 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1186 return;
dudmuck 0:8f0d0ae0a077 1187 }
dudmuck 0:8f0d0ae0a077 1188 }
dudmuck 0:8f0d0ae0a077 1189 else
dudmuck 0:8f0d0ae0a077 1190 {
dudmuck 0:8f0d0ae0a077 1191 multicast = 0;
dudmuck 0:8f0d0ae0a077 1192 nwkSKey = LoRaMacNwkSKey;
dudmuck 0:8f0d0ae0a077 1193 appSKey = LoRaMacAppSKey;
dudmuck 0:8f0d0ae0a077 1194 downLinkCounter = DownLinkCounter;
dudmuck 0:8f0d0ae0a077 1195 }
dudmuck 0:8f0d0ae0a077 1196
Wayne Roberts 29:ad409c68c0a6 1197 fCtrl.Value = Radio::radio.rx_buf[pktHeaderLen++];
Wayne Roberts 29:ad409c68c0a6 1198
Wayne Roberts 29:ad409c68c0a6 1199 sequenceCounter = ( uint16_t )Radio::radio.rx_buf[pktHeaderLen++];
Wayne Roberts 29:ad409c68c0a6 1200 sequenceCounter |= ( uint16_t )Radio::radio.rx_buf[pktHeaderLen++] << 8;
dudmuck 0:8f0d0ae0a077 1201
dudmuck 0:8f0d0ae0a077 1202 appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
dudmuck 0:8f0d0ae0a077 1203
Wayne Roberts 29:ad409c68c0a6 1204 micRx |= ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN];
Wayne Roberts 29:ad409c68c0a6 1205 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 1] << 8 );
Wayne Roberts 29:ad409c68c0a6 1206 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 2] << 16 );
Wayne Roberts 29:ad409c68c0a6 1207 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 3] << 24 );
dudmuck 0:8f0d0ae0a077 1208
dudmuck 0:8f0d0ae0a077 1209 sequenceCounterPrev = ( uint16_t )downLinkCounter;
dudmuck 0:8f0d0ae0a077 1210 sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev );
dudmuck 0:8f0d0ae0a077 1211
dudmuck 0:8f0d0ae0a077 1212 if( sequenceCounterDiff < ( 1 << 15 ) )
dudmuck 0:8f0d0ae0a077 1213 {
dudmuck 0:8f0d0ae0a077 1214 downLinkCounter += sequenceCounterDiff;
Wayne Roberts 29:ad409c68c0a6 1215 LoRaMacComputeMic( Radio::radio.rx_buf, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
dudmuck 0:8f0d0ae0a077 1216 if( micRx == mic )
dudmuck 0:8f0d0ae0a077 1217 {
dudmuck 0:8f0d0ae0a077 1218 isMicOk = true;
dudmuck 0:8f0d0ae0a077 1219 }
dudmuck 0:8f0d0ae0a077 1220 }
dudmuck 0:8f0d0ae0a077 1221 else
dudmuck 0:8f0d0ae0a077 1222 {
dudmuck 0:8f0d0ae0a077 1223 // check for sequence roll-over
dudmuck 0:8f0d0ae0a077 1224 uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff;
Wayne Roberts 29:ad409c68c0a6 1225 LoRaMacComputeMic( Radio::radio.rx_buf, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic );
dudmuck 0:8f0d0ae0a077 1226 if( micRx == mic )
dudmuck 0:8f0d0ae0a077 1227 {
dudmuck 0:8f0d0ae0a077 1228 isMicOk = true;
dudmuck 0:8f0d0ae0a077 1229 downLinkCounter = downLinkCounterTmp;
dudmuck 0:8f0d0ae0a077 1230 }
dudmuck 0:8f0d0ae0a077 1231 }
dudmuck 0:8f0d0ae0a077 1232
dudmuck 0:8f0d0ae0a077 1233 // Check for a the maximum allowed counter difference
dudmuck 0:8f0d0ae0a077 1234 if( sequenceCounterDiff >= MAX_FCNT_GAP )
dudmuck 0:8f0d0ae0a077 1235 {
dudmuck 0:8f0d0ae0a077 1236 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
dudmuck 0:8f0d0ae0a077 1237 McpsIndication.DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1238 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1239 return;
dudmuck 0:8f0d0ae0a077 1240 }
dudmuck 0:8f0d0ae0a077 1241
dudmuck 0:8f0d0ae0a077 1242 if( isMicOk == true )
dudmuck 0:8f0d0ae0a077 1243 {
dudmuck 0:8f0d0ae0a077 1244 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1245 McpsIndication.Multicast = multicast;
dudmuck 0:8f0d0ae0a077 1246 McpsIndication.FramePending = fCtrl.Bits.FPending;
dudmuck 0:8f0d0ae0a077 1247 McpsIndication.Buffer = NULL;
dudmuck 0:8f0d0ae0a077 1248 McpsIndication.BufferSize = 0;
dudmuck 0:8f0d0ae0a077 1249 McpsIndication.DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1250
dudmuck 0:8f0d0ae0a077 1251 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1252
dudmuck 0:8f0d0ae0a077 1253 MacCommandsBufferToRepeatIndex = 0;
dudmuck 0:8f0d0ae0a077 1254
dudmuck 0:8f0d0ae0a077 1255 // Update 32 bits downlink counter
dudmuck 0:8f0d0ae0a077 1256 if( multicast == 1 )
dudmuck 0:8f0d0ae0a077 1257 {
dudmuck 0:8f0d0ae0a077 1258 McpsIndication.McpsIndication = MCPS_MULTICAST;
dudmuck 0:8f0d0ae0a077 1259
dudmuck 0:8f0d0ae0a077 1260 if( ( curMulticastParams->DownLinkCounter == downLinkCounter ) &&
dudmuck 0:8f0d0ae0a077 1261 ( curMulticastParams->DownLinkCounter != 0 ) )
dudmuck 0:8f0d0ae0a077 1262 {
dudmuck 0:8f0d0ae0a077 1263 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
dudmuck 0:8f0d0ae0a077 1264 McpsIndication.DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1265 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1266 return;
dudmuck 0:8f0d0ae0a077 1267 }
dudmuck 0:8f0d0ae0a077 1268 curMulticastParams->DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1269 }
dudmuck 0:8f0d0ae0a077 1270 else
dudmuck 0:8f0d0ae0a077 1271 {
dudmuck 0:8f0d0ae0a077 1272 if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
dudmuck 0:8f0d0ae0a077 1273 {
Wayne Roberts 29:ad409c68c0a6 1274 LoRaMacFlags.Bits.SrvAckRequested = true;
dudmuck 0:8f0d0ae0a077 1275 McpsIndication.McpsIndication = MCPS_CONFIRMED;
dudmuck 0:8f0d0ae0a077 1276
dudmuck 0:8f0d0ae0a077 1277 if( ( DownLinkCounter == downLinkCounter ) &&
dudmuck 0:8f0d0ae0a077 1278 ( DownLinkCounter != 0 ) )
dudmuck 0:8f0d0ae0a077 1279 {
dudmuck 0:8f0d0ae0a077 1280 // Duplicated confirmed downlink. Skip indication.
dudmuck 0:8f0d0ae0a077 1281 // In this case, the MAC layer shall accept the MAC commands
dudmuck 0:8f0d0ae0a077 1282 // which are included in the downlink retransmission.
dudmuck 0:8f0d0ae0a077 1283 // It should not provide the same frame to the application
dudmuck 0:8f0d0ae0a077 1284 // layer again.
dudmuck 0:8f0d0ae0a077 1285 skipIndication = true;
dudmuck 0:8f0d0ae0a077 1286 }
dudmuck 0:8f0d0ae0a077 1287 }
dudmuck 0:8f0d0ae0a077 1288 else
dudmuck 0:8f0d0ae0a077 1289 {
Wayne Roberts 29:ad409c68c0a6 1290 LoRaMacFlags.Bits.SrvAckRequested = false;
dudmuck 0:8f0d0ae0a077 1291 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
dudmuck 0:8f0d0ae0a077 1292
dudmuck 0:8f0d0ae0a077 1293 if( ( DownLinkCounter == downLinkCounter ) &&
dudmuck 0:8f0d0ae0a077 1294 ( DownLinkCounter != 0 ) )
dudmuck 0:8f0d0ae0a077 1295 {
dudmuck 0:8f0d0ae0a077 1296 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
dudmuck 0:8f0d0ae0a077 1297 McpsIndication.DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1298 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1299 return;
dudmuck 0:8f0d0ae0a077 1300 }
dudmuck 0:8f0d0ae0a077 1301 }
dudmuck 0:8f0d0ae0a077 1302 DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1303 }
dudmuck 0:8f0d0ae0a077 1304
dudmuck 0:8f0d0ae0a077 1305 // This must be done before parsing the payload and the MAC commands.
dudmuck 0:8f0d0ae0a077 1306 // We need to reset the MacCommandsBufferIndex here, since we need
dudmuck 0:8f0d0ae0a077 1307 // to take retransmissions and repititions into account. Error cases
dudmuck 0:8f0d0ae0a077 1308 // will be handled in function OnMacStateCheckTimerEvent.
dudmuck 0:8f0d0ae0a077 1309 if( McpsConfirm.McpsRequest == MCPS_CONFIRMED )
dudmuck 0:8f0d0ae0a077 1310 {
dudmuck 0:8f0d0ae0a077 1311 if( fCtrl.Bits.Ack == 1 )
dudmuck 0:8f0d0ae0a077 1312 {// Reset MacCommandsBufferIndex when we have received an ACK.
dudmuck 0:8f0d0ae0a077 1313 MacCommandsBufferIndex = 0;
dudmuck 0:8f0d0ae0a077 1314 }
dudmuck 0:8f0d0ae0a077 1315 }
dudmuck 0:8f0d0ae0a077 1316 else
dudmuck 0:8f0d0ae0a077 1317 {// Reset the variable if we have received any valid frame.
dudmuck 0:8f0d0ae0a077 1318 MacCommandsBufferIndex = 0;
dudmuck 0:8f0d0ae0a077 1319 }
dudmuck 0:8f0d0ae0a077 1320
dudmuck 0:8f0d0ae0a077 1321 // Process payload and MAC commands
dudmuck 0:8f0d0ae0a077 1322 if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
dudmuck 0:8f0d0ae0a077 1323 {
Wayne Roberts 29:ad409c68c0a6 1324 port = Radio::radio.rx_buf[appPayloadStartIndex++];
dudmuck 0:8f0d0ae0a077 1325 frameLen = ( size - 4 ) - appPayloadStartIndex;
dudmuck 0:8f0d0ae0a077 1326
dudmuck 0:8f0d0ae0a077 1327 McpsIndication.Port = port;
dudmuck 0:8f0d0ae0a077 1328
dudmuck 0:8f0d0ae0a077 1329 if( port == 0 )
dudmuck 0:8f0d0ae0a077 1330 {
dudmuck 0:8f0d0ae0a077 1331 // Only allow frames which do not have fOpts
dudmuck 0:8f0d0ae0a077 1332 if( fCtrl.Bits.FOptsLen == 0 )
dudmuck 0:8f0d0ae0a077 1333 {
Wayne Roberts 29:ad409c68c0a6 1334 uint8_t macDecrypt[16];
Wayne Roberts 29:ad409c68c0a6 1335 LoRaMacPayloadDecrypt( Radio::radio.rx_buf + appPayloadStartIndex,
dudmuck 0:8f0d0ae0a077 1336 frameLen,
dudmuck 0:8f0d0ae0a077 1337 nwkSKey,
dudmuck 0:8f0d0ae0a077 1338 address,
dudmuck 0:8f0d0ae0a077 1339 DOWN_LINK,
dudmuck 0:8f0d0ae0a077 1340 downLinkCounter,
Wayne Roberts 29:ad409c68c0a6 1341 macDecrypt);
dudmuck 0:8f0d0ae0a077 1342
dudmuck 0:8f0d0ae0a077 1343 // Decode frame payload MAC commands
Wayne Roberts 29:ad409c68c0a6 1344 ProcessMacCommands( macDecrypt, 0, frameLen, snr );
dudmuck 0:8f0d0ae0a077 1345 }
dudmuck 0:8f0d0ae0a077 1346 else
dudmuck 0:8f0d0ae0a077 1347 {
dudmuck 0:8f0d0ae0a077 1348 skipIndication = true;
dudmuck 0:8f0d0ae0a077 1349 }
dudmuck 0:8f0d0ae0a077 1350 }
dudmuck 0:8f0d0ae0a077 1351 else
dudmuck 0:8f0d0ae0a077 1352 {
dudmuck 0:8f0d0ae0a077 1353 if( fCtrl.Bits.FOptsLen > 0 )
dudmuck 0:8f0d0ae0a077 1354 {
dudmuck 0:8f0d0ae0a077 1355 // Decode Options field MAC commands. Omit the fPort.
Wayne Roberts 29:ad409c68c0a6 1356 ProcessMacCommands( Radio::radio.rx_buf, 8, appPayloadStartIndex - 1, snr );
dudmuck 0:8f0d0ae0a077 1357 }
dudmuck 0:8f0d0ae0a077 1358
Wayne Roberts 29:ad409c68c0a6 1359 LoRaMacPayloadDecrypt( Radio::radio.rx_buf + appPayloadStartIndex,
dudmuck 0:8f0d0ae0a077 1360 frameLen,
dudmuck 0:8f0d0ae0a077 1361 appSKey,
dudmuck 0:8f0d0ae0a077 1362 address,
dudmuck 0:8f0d0ae0a077 1363 DOWN_LINK,
dudmuck 0:8f0d0ae0a077 1364 downLinkCounter,
Wayne Roberts 29:ad409c68c0a6 1365 rxFRMPayload);
dudmuck 0:8f0d0ae0a077 1366
dudmuck 0:8f0d0ae0a077 1367 if( skipIndication == false )
dudmuck 0:8f0d0ae0a077 1368 {
Wayne Roberts 29:ad409c68c0a6 1369 McpsIndication.Buffer = rxFRMPayload;
dudmuck 0:8f0d0ae0a077 1370 McpsIndication.BufferSize = frameLen;
dudmuck 0:8f0d0ae0a077 1371 McpsIndication.RxData = true;
dudmuck 0:8f0d0ae0a077 1372 }
dudmuck 0:8f0d0ae0a077 1373 }
dudmuck 0:8f0d0ae0a077 1374 }
dudmuck 0:8f0d0ae0a077 1375 else
dudmuck 0:8f0d0ae0a077 1376 {
dudmuck 0:8f0d0ae0a077 1377 if( fCtrl.Bits.FOptsLen > 0 )
dudmuck 0:8f0d0ae0a077 1378 {
dudmuck 0:8f0d0ae0a077 1379 // Decode Options field MAC commands
Wayne Roberts 29:ad409c68c0a6 1380 ProcessMacCommands( Radio::radio.rx_buf, 8, appPayloadStartIndex, snr );
dudmuck 0:8f0d0ae0a077 1381 }
dudmuck 0:8f0d0ae0a077 1382 }
dudmuck 0:8f0d0ae0a077 1383
dudmuck 0:8f0d0ae0a077 1384 if( skipIndication == false )
dudmuck 0:8f0d0ae0a077 1385 {
dudmuck 0:8f0d0ae0a077 1386 // Check if the frame is an acknowledgement
dudmuck 0:8f0d0ae0a077 1387 if( fCtrl.Bits.Ack == 1 )
dudmuck 0:8f0d0ae0a077 1388 {
dudmuck 0:8f0d0ae0a077 1389 McpsConfirm.AckReceived = true;
dudmuck 0:8f0d0ae0a077 1390 McpsIndication.AckReceived = true;
dudmuck 0:8f0d0ae0a077 1391
dudmuck 0:8f0d0ae0a077 1392 // Stop the AckTimeout timer as no more retransmissions
dudmuck 0:8f0d0ae0a077 1393 // are needed.
dudmuck 0:8f0d0ae0a077 1394 }
dudmuck 0:8f0d0ae0a077 1395 else
dudmuck 0:8f0d0ae0a077 1396 {
dudmuck 0:8f0d0ae0a077 1397 McpsConfirm.AckReceived = false;
dudmuck 0:8f0d0ae0a077 1398 }
dudmuck 0:8f0d0ae0a077 1399 }
dudmuck 0:8f0d0ae0a077 1400 // Provide always an indication, skip the callback to the user application,
dudmuck 0:8f0d0ae0a077 1401 // in case of a confirmed downlink retransmission.
dudmuck 0:8f0d0ae0a077 1402 LoRaMacFlags.Bits.McpsInd = 1;
dudmuck 0:8f0d0ae0a077 1403 LoRaMacFlags.Bits.McpsIndSkip = skipIndication;
dudmuck 0:8f0d0ae0a077 1404 }
dudmuck 0:8f0d0ae0a077 1405 else
dudmuck 0:8f0d0ae0a077 1406 {
dudmuck 0:8f0d0ae0a077 1407 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
dudmuck 5:c108560af4c3 1408 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
dudmuck 0:8f0d0ae0a077 1409 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1410 return;
dudmuck 0:8f0d0ae0a077 1411 }
dudmuck 0:8f0d0ae0a077 1412 }
dudmuck 0:8f0d0ae0a077 1413 break;
dudmuck 0:8f0d0ae0a077 1414 case FRAME_TYPE_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 1415 {
dudmuck 0:8f0d0ae0a077 1416 McpsIndication.McpsIndication = MCPS_PROPRIETARY;
dudmuck 0:8f0d0ae0a077 1417 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 1418 McpsIndication.Buffer = Radio::radio.rx_buf;
dudmuck 0:8f0d0ae0a077 1419 McpsIndication.BufferSize = size - pktHeaderLen;
dudmuck 0:8f0d0ae0a077 1420
dudmuck 0:8f0d0ae0a077 1421 LoRaMacFlags.Bits.McpsInd = 1;
dudmuck 0:8f0d0ae0a077 1422 break;
dudmuck 0:8f0d0ae0a077 1423 }
dudmuck 0:8f0d0ae0a077 1424 default:
dudmuck 2:f2d9aa163652 1425 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE;
dudmuck 5:c108560af4c3 1426 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE;
Wayne Roberts 34:9c8966cd66a2 1427 mac_printf("%d:macHdr:%02x(%f,%f) ", size, macHdr.Value, rssi, snr);
dudmuck 0:8f0d0ae0a077 1428 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1429 break;
dudmuck 0:8f0d0ae0a077 1430 }
dudmuck 0:8f0d0ae0a077 1431 LoRaMacFlags.Bits.MacDone = 1;
dudmuck 0:8f0d0ae0a077 1432
dudmuck 16:915815632c1f 1433 application_callbacks();
dudmuck 16:915815632c1f 1434
Wayne Roberts 29:ad409c68c0a6 1435 } // ..OnRadioRxDone()
dudmuck 16:915815632c1f 1436
dudmuck 0:8f0d0ae0a077 1437 static void OnRadioTxTimeout( void )
dudmuck 0:8f0d0ae0a077 1438 {
Wayne Roberts 29:ad409c68c0a6 1439 Radio::Sleep( );
dudmuck 0:8f0d0ae0a077 1440
dudmuck 0:8f0d0ae0a077 1441 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 1442 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 1443 LoRaMacFlags.Bits.MacDone = 1;
dudmuck 0:8f0d0ae0a077 1444 }
dudmuck 0:8f0d0ae0a077 1445
dudmuck 0:8f0d0ae0a077 1446 static void OnRadioRxError( void )
dudmuck 0:8f0d0ae0a077 1447 {
Wayne Roberts 29:ad409c68c0a6 1448 Radio::Sleep( );
Wayne Roberts 29:ad409c68c0a6 1449
Wayne Roberts 29:ad409c68c0a6 1450 if (LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 1451 {
dudmuck 0:8f0d0ae0a077 1452 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR;
dudmuck 0:8f0d0ae0a077 1453 }
dudmuck 0:8f0d0ae0a077 1454 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR;
dudmuck 0:8f0d0ae0a077 1455
Wayne Roberts 29:ad409c68c0a6 1456 LoRaMacFlags.Bits.MacDone = 1;
dudmuck 0:8f0d0ae0a077 1457 }
dudmuck 0:8f0d0ae0a077 1458
dudmuck 16:915815632c1f 1459 static void
dudmuck 16:915815632c1f 1460 join_send()
dudmuck 16:915815632c1f 1461 {
Wayne Roberts 29:ad409c68c0a6 1462 LoRaMacFlags.Bits.join_send = 1;
dudmuck 20:42839629a5dc 1463 }
dudmuck 20:42839629a5dc 1464
dudmuck 25:fed9d5b77183 1465 static void ScheduleTx( void )
dudmuck 25:fed9d5b77183 1466 {
Wayne Roberts 29:ad409c68c0a6 1467 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
Wayne Roberts 29:ad409c68c0a6 1468 LoRaMacFlags.Bits.send = 1; // immediately send join asychronously
dudmuck 25:fed9d5b77183 1469 else
dudmuck 25:fed9d5b77183 1470 LoRaMacFlags.Bits.uplink_pending = 1; // send synchronously
dudmuck 25:fed9d5b77183 1471 }
dudmuck 25:fed9d5b77183 1472
dudmuck 20:42839629a5dc 1473 static void
dudmuck 20:42839629a5dc 1474 join_send_bh()
dudmuck 20:42839629a5dc 1475 {
dudmuck 16:915815632c1f 1476 if (JoinRequestTrials < MaxJoinRequestTrials) {
dudmuck 16:915815632c1f 1477 LoRaMacHeader_t macHdr;
dudmuck 16:915815632c1f 1478 LoRaMacFrameCtrl_t fCtrl;
Wayne Roberts 29:ad409c68c0a6 1479
dudmuck 16:915815632c1f 1480 if (++Channel == LORA_MAX_NB_CHANNELS)
dudmuck 16:915815632c1f 1481 Channel = 0;
Wayne Roberts 29:ad409c68c0a6 1482 mac_printf("<join-ch%u>", Channel);
Wayne Roberts 29:ad409c68c0a6 1483
dudmuck 16:915815632c1f 1484 macHdr.Value = 0;
dudmuck 16:915815632c1f 1485 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
Wayne Roberts 29:ad409c68c0a6 1486
dudmuck 16:915815632c1f 1487 fCtrl.Value = 0;
dudmuck 16:915815632c1f 1488 fCtrl.Bits.Adr = 0;
Wayne Roberts 29:ad409c68c0a6 1489
dudmuck 16:915815632c1f 1490 /* In case of join request retransmissions, the stack must prepare
dudmuck 16:915815632c1f 1491 * the frame again, because the network server keeps track of the random
dudmuck 16:915815632c1f 1492 * LoRaMacDevNonce values to prevent reply attacks. */
dudmuck 16:915815632c1f 1493 PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 );
Wayne Roberts 29:ad409c68c0a6 1494
dudmuck 16:915815632c1f 1495 ScheduleTx();
dudmuck 16:915815632c1f 1496 } else {
dudmuck 16:915815632c1f 1497 MlmeConfirm.MlmeRequest = MLME_JOIN;
dudmuck 16:915815632c1f 1498 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
dudmuck 16:915815632c1f 1499 LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
dudmuck 16:915815632c1f 1500 }
Wayne Roberts 29:ad409c68c0a6 1501 } // ..join_send_bh()
dudmuck 16:915815632c1f 1502
dudmuck 0:8f0d0ae0a077 1503 static void OnRadioRxTimeout( void )
dudmuck 0:8f0d0ae0a077 1504 {
Wayne Roberts 29:ad409c68c0a6 1505 Radio::Sleep( );
Wayne Roberts 29:ad409c68c0a6 1506
Wayne Roberts 34:9c8966cd66a2 1507 pc_printf("OnRadioRxTimeout eb%u\r\n", LoRaMacFlags.Bits.expecting_beacon);
Wayne Roberts 29:ad409c68c0a6 1508 if (LoRaMacFlags.Bits.expecting_beacon) {
Wayne Roberts 29:ad409c68c0a6 1509 float ourErrSecs = BeaconCtx.known_working_BeaconRxTimerError_us / 1000000.0;
dudmuck 0:8f0d0ae0a077 1510
Wayne Roberts 29:ad409c68c0a6 1511 LoRaMacFlags.Bits.expecting_beacon = false;
Wayne Roberts 29:ad409c68c0a6 1512
Wayne Roberts 34:9c8966cd66a2 1513 microseconds rx_next_us(BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us);
Wayne Roberts 34:9c8966cd66a2 1514 BeaconCtx.rx_setup_at += rx_next_us;
Wayne Roberts 34:9c8966cd66a2 1515 microseconds pre_rx_us(PPM_BEACON_INTERVAL / 4); // come up early when missed
Wayne Roberts 34:9c8966cd66a2 1516 BeaconCtx.rx_setup_at -= pre_rx_us;
Wayne Roberts 30:1c35c4f56e50 1517 us_to_nSymbTimeout(BeaconCtx.SymbolTimeout_us + PPM_BEACON_INTERVAL);
Wayne Roberts 30:1c35c4f56e50 1518 mac_printf("beacon timeout ourErr:%f SymbTo:%u(%uus)\r\n", ourErrSecs, BeaconCtx.nSymbsTimeout, BeaconCtx.SymbolTimeout_us);
Wayne Roberts 29:ad409c68c0a6 1519
Wayne Roberts 34:9c8966cd66a2 1520 BeaconCtx.timeout_rx.attach_absolute(&OnRxBeaconSetup, BeaconCtx.rx_setup_at - mcu_wakeup_latency);
Wayne Roberts 34:9c8966cd66a2 1521 microseconds guard_us(BEACON_GUARD_us);
Wayne Roberts 34:9c8966cd66a2 1522 BeaconCtx.timeout_guard.attach_absolute(&guard_callback, BeaconCtx.rx_setup_at - (guard_us + mcu_wakeup_latency));
Wayne Roberts 29:ad409c68c0a6 1523
Wayne Roberts 29:ad409c68c0a6 1524 if (++BeaconCtx.num_missed > BEACONS_MISSED_LIMIT) {
Wayne Roberts 29:ad409c68c0a6 1525 LoRaMacFlags.Bits.reJoin = 1;
Wayne Roberts 29:ad409c68c0a6 1526 } else {
Wayne Roberts 29:ad409c68c0a6 1527 MlmeIndication.MlmeIndication = MLME_BEACON;
Wayne Roberts 29:ad409c68c0a6 1528 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_BEACON_LOST;
Wayne Roberts 29:ad409c68c0a6 1529 LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
Wayne Roberts 29:ad409c68c0a6 1530 }
Wayne Roberts 29:ad409c68c0a6 1531
Wayne Roberts 34:9c8966cd66a2 1532 microseconds base((BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us) * BeaconCtx.num_missed);
Wayne Roberts 34:9c8966cd66a2 1533 BeaconCtx.sendAt = BeaconCtx.LastBeaconRxAt + base;
Wayne Roberts 34:9c8966cd66a2 1534 microseconds tx_slot_us(BeaconCtx.tx_slot_offset * PING_SLOT_RESOLUTION_us);
Wayne Roberts 34:9c8966cd66a2 1535 BeaconCtx.sendAt += tx_slot_us;
Wayne Roberts 34:9c8966cd66a2 1536 tx_timeout.attach_absolute(&send_callback, BeaconCtx.sendAt - mcu_wakeup_latency);
Wayne Roberts 29:ad409c68c0a6 1537
Wayne Roberts 30:1c35c4f56e50 1538 BeaconCtx.num_consecutive_ok = 0;
dudmuck 16:915815632c1f 1539 } else {
dudmuck 25:fed9d5b77183 1540 if (LoRaMacFlags.Bits.MlmeReq && ( MlmeConfirm.MlmeRequest == MLME_JOIN )) {
dudmuck 25:fed9d5b77183 1541 /* no join accept received: join retry */
Wayne Roberts 34:9c8966cd66a2 1542 microseconds us((JoinRequestTrials*20000) + randr(0, 70000));
Wayne Roberts 34:9c8966cd66a2 1543 tx_timeout.attach(&join_send, us - mcu_wakeup_latency);
dudmuck 25:fed9d5b77183 1544 }
dudmuck 0:8f0d0ae0a077 1545 }
dudmuck 0:8f0d0ae0a077 1546
Wayne Roberts 29:ad409c68c0a6 1547 if (LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 1548 {
dudmuck 0:8f0d0ae0a077 1549 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 1550 }
dudmuck 0:8f0d0ae0a077 1551 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 1552 LoRaMacFlags.Bits.MacDone = 1;
Wayne Roberts 29:ad409c68c0a6 1553
dudmuck 16:915815632c1f 1554 application_callbacks();
dudmuck 1:53c30224eda8 1555 } // ..OnRadioRxTimeout();
dudmuck 0:8f0d0ae0a077 1556
dudmuck 0:8f0d0ae0a077 1557 static void OnAckTimeoutTimerEvent( void )
dudmuck 0:8f0d0ae0a077 1558 {
dudmuck 0:8f0d0ae0a077 1559 }
dudmuck 0:8f0d0ae0a077 1560
dudmuck 0:8f0d0ae0a077 1561 static bool ValueInRange( int8_t value, int8_t min, int8_t max )
dudmuck 0:8f0d0ae0a077 1562 {
dudmuck 0:8f0d0ae0a077 1563 if( ( value >= min ) && ( value <= max ) )
dudmuck 0:8f0d0ae0a077 1564 {
dudmuck 0:8f0d0ae0a077 1565 return true;
dudmuck 0:8f0d0ae0a077 1566 }
dudmuck 0:8f0d0ae0a077 1567 return false;
dudmuck 0:8f0d0ae0a077 1568 }
dudmuck 0:8f0d0ae0a077 1569
dudmuck 0:8f0d0ae0a077 1570 static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
dudmuck 0:8f0d0ae0a077 1571 {
dudmuck 0:8f0d0ae0a077 1572 LoRaMacStatus_t status = LORAMAC_STATUS_BUSY;
dudmuck 0:8f0d0ae0a077 1573 // The maximum buffer length must take MAC commands to re-send into account.
dudmuck 0:8f0d0ae0a077 1574 uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex;
dudmuck 0:8f0d0ae0a077 1575
dudmuck 0:8f0d0ae0a077 1576 switch( cmd )
dudmuck 0:8f0d0ae0a077 1577 {
dudmuck 0:8f0d0ae0a077 1578 case MOTE_MAC_LINK_CHECK_REQ:
dudmuck 0:8f0d0ae0a077 1579 if( MacCommandsBufferIndex < bufLen )
dudmuck 0:8f0d0ae0a077 1580 {
dudmuck 0:8f0d0ae0a077 1581 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
dudmuck 0:8f0d0ae0a077 1582 // No payload for this command
dudmuck 0:8f0d0ae0a077 1583 status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1584 }
dudmuck 0:8f0d0ae0a077 1585 break;
dudmuck 0:8f0d0ae0a077 1586 case MOTE_MAC_RX_PARAM_SETUP_ANS:
dudmuck 0:8f0d0ae0a077 1587 if( MacCommandsBufferIndex < ( bufLen - 1 ) )
dudmuck 0:8f0d0ae0a077 1588 {
dudmuck 0:8f0d0ae0a077 1589 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
dudmuck 0:8f0d0ae0a077 1590 // Status: Datarate ACK, Channel ACK
dudmuck 0:8f0d0ae0a077 1591 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
dudmuck 0:8f0d0ae0a077 1592 status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1593 }
dudmuck 0:8f0d0ae0a077 1594 break;
dudmuck 0:8f0d0ae0a077 1595 case MOTE_MAC_DEV_STATUS_ANS:
dudmuck 0:8f0d0ae0a077 1596 if( MacCommandsBufferIndex < ( bufLen - 2 ) )
dudmuck 0:8f0d0ae0a077 1597 {
dudmuck 0:8f0d0ae0a077 1598 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
dudmuck 0:8f0d0ae0a077 1599 // 1st byte Battery
dudmuck 0:8f0d0ae0a077 1600 // 2nd byte Margin
dudmuck 0:8f0d0ae0a077 1601 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
dudmuck 0:8f0d0ae0a077 1602 MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
dudmuck 0:8f0d0ae0a077 1603 status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1604 }
dudmuck 0:8f0d0ae0a077 1605 break;
dudmuck 0:8f0d0ae0a077 1606 case MOTE_MAC_RX_TIMING_SETUP_ANS:
dudmuck 0:8f0d0ae0a077 1607 if( MacCommandsBufferIndex < bufLen )
dudmuck 0:8f0d0ae0a077 1608 {
dudmuck 0:8f0d0ae0a077 1609 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
dudmuck 0:8f0d0ae0a077 1610 // No payload for this answer
dudmuck 0:8f0d0ae0a077 1611 status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1612 }
dudmuck 0:8f0d0ae0a077 1613 break;
dudmuck 0:8f0d0ae0a077 1614 default:
dudmuck 0:8f0d0ae0a077 1615 return LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 1616 }
dudmuck 0:8f0d0ae0a077 1617 if( status == LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 1618 {
dudmuck 0:8f0d0ae0a077 1619 MacCommandsInNextTx = true;
dudmuck 0:8f0d0ae0a077 1620 }
dudmuck 0:8f0d0ae0a077 1621 return status;
dudmuck 0:8f0d0ae0a077 1622 }
dudmuck 0:8f0d0ae0a077 1623
dudmuck 0:8f0d0ae0a077 1624 static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut )
dudmuck 0:8f0d0ae0a077 1625 {
dudmuck 0:8f0d0ae0a077 1626 uint8_t i = 0;
dudmuck 0:8f0d0ae0a077 1627 uint8_t cmdCount = 0;
dudmuck 0:8f0d0ae0a077 1628
dudmuck 0:8f0d0ae0a077 1629 if( ( cmdBufIn == NULL ) || ( cmdBufOut == NULL ) )
dudmuck 0:8f0d0ae0a077 1630 {
dudmuck 0:8f0d0ae0a077 1631 return 0;
dudmuck 0:8f0d0ae0a077 1632 }
dudmuck 0:8f0d0ae0a077 1633
dudmuck 0:8f0d0ae0a077 1634 for( i = 0; i < length; i++ )
dudmuck 0:8f0d0ae0a077 1635 {
dudmuck 0:8f0d0ae0a077 1636 switch( cmdBufIn[i] )
dudmuck 0:8f0d0ae0a077 1637 {
dudmuck 0:8f0d0ae0a077 1638 // STICKY
dudmuck 0:8f0d0ae0a077 1639 case MOTE_MAC_RX_PARAM_SETUP_ANS:
dudmuck 0:8f0d0ae0a077 1640 {
dudmuck 0:8f0d0ae0a077 1641 cmdBufOut[cmdCount++] = cmdBufIn[i++];
dudmuck 0:8f0d0ae0a077 1642 cmdBufOut[cmdCount++] = cmdBufIn[i];
dudmuck 0:8f0d0ae0a077 1643 break;
dudmuck 0:8f0d0ae0a077 1644 }
dudmuck 0:8f0d0ae0a077 1645 case MOTE_MAC_RX_TIMING_SETUP_ANS:
dudmuck 0:8f0d0ae0a077 1646 {
dudmuck 0:8f0d0ae0a077 1647 cmdBufOut[cmdCount++] = cmdBufIn[i];
dudmuck 0:8f0d0ae0a077 1648 break;
dudmuck 0:8f0d0ae0a077 1649 }
dudmuck 0:8f0d0ae0a077 1650 // NON-STICKY
dudmuck 0:8f0d0ae0a077 1651 case MOTE_MAC_DEV_STATUS_ANS:
dudmuck 0:8f0d0ae0a077 1652 { // 2 bytes payload
dudmuck 0:8f0d0ae0a077 1653 i += 2;
dudmuck 0:8f0d0ae0a077 1654 break;
dudmuck 0:8f0d0ae0a077 1655 }
dudmuck 0:8f0d0ae0a077 1656 case MOTE_MAC_LINK_CHECK_REQ:
dudmuck 0:8f0d0ae0a077 1657 { // 0 byte payload
dudmuck 0:8f0d0ae0a077 1658 break;
dudmuck 0:8f0d0ae0a077 1659 }
dudmuck 0:8f0d0ae0a077 1660 default:
dudmuck 0:8f0d0ae0a077 1661 break;
dudmuck 0:8f0d0ae0a077 1662 }
dudmuck 0:8f0d0ae0a077 1663 }
dudmuck 0:8f0d0ae0a077 1664
dudmuck 0:8f0d0ae0a077 1665 return cmdCount;
dudmuck 0:8f0d0ae0a077 1666 }
dudmuck 0:8f0d0ae0a077 1667
dudmuck 0:8f0d0ae0a077 1668 static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr )
dudmuck 0:8f0d0ae0a077 1669 {
dudmuck 0:8f0d0ae0a077 1670 while( macIndex < commandsSize )
dudmuck 0:8f0d0ae0a077 1671 {
dudmuck 0:8f0d0ae0a077 1672 // Decode Frame MAC commands
dudmuck 0:8f0d0ae0a077 1673 switch( payload[macIndex++] )
dudmuck 0:8f0d0ae0a077 1674 {
dudmuck 0:8f0d0ae0a077 1675 case SRV_MAC_LINK_CHECK_ANS:
dudmuck 0:8f0d0ae0a077 1676 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1677 MlmeConfirm.DemodMargin = payload[macIndex++];
dudmuck 0:8f0d0ae0a077 1678 MlmeConfirm.NbGateways = payload[macIndex++];
dudmuck 0:8f0d0ae0a077 1679 break;
dudmuck 0:8f0d0ae0a077 1680 case SRV_MAC_DEV_STATUS_REQ:
dudmuck 0:8f0d0ae0a077 1681 {
dudmuck 0:8f0d0ae0a077 1682 uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
dudmuck 0:8f0d0ae0a077 1683 if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) )
dudmuck 0:8f0d0ae0a077 1684 {
dudmuck 0:8f0d0ae0a077 1685 batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
dudmuck 0:8f0d0ae0a077 1686 }
dudmuck 0:8f0d0ae0a077 1687 AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
dudmuck 0:8f0d0ae0a077 1688 break;
dudmuck 0:8f0d0ae0a077 1689 }
dudmuck 0:8f0d0ae0a077 1690 case SRV_MAC_RX_TIMING_SETUP_REQ:
dudmuck 0:8f0d0ae0a077 1691 {
dudmuck 0:8f0d0ae0a077 1692 uint8_t delay = payload[macIndex++] & 0x0F;
dudmuck 0:8f0d0ae0a077 1693
dudmuck 0:8f0d0ae0a077 1694 if( delay == 0 )
dudmuck 0:8f0d0ae0a077 1695 {
dudmuck 0:8f0d0ae0a077 1696 delay++;
dudmuck 0:8f0d0ae0a077 1697 }
dudmuck 0:8f0d0ae0a077 1698 LoRaMacParams.ReceiveDelay_us = delay * 1e6;
dudmuck 0:8f0d0ae0a077 1699 AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
dudmuck 0:8f0d0ae0a077 1700 }
dudmuck 0:8f0d0ae0a077 1701 break;
dudmuck 0:8f0d0ae0a077 1702 default:
dudmuck 0:8f0d0ae0a077 1703 // Unknown command. ABORT MAC commands processing
dudmuck 0:8f0d0ae0a077 1704 return;
dudmuck 0:8f0d0ae0a077 1705 }
dudmuck 0:8f0d0ae0a077 1706 }
dudmuck 0:8f0d0ae0a077 1707 }
dudmuck 0:8f0d0ae0a077 1708
dudmuck 0:8f0d0ae0a077 1709 LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
dudmuck 0:8f0d0ae0a077 1710 {
dudmuck 0:8f0d0ae0a077 1711 LoRaMacFrameCtrl_t fCtrl;
dudmuck 0:8f0d0ae0a077 1712 LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 1713
dudmuck 0:8f0d0ae0a077 1714 fCtrl.Value = 0;
dudmuck 0:8f0d0ae0a077 1715 fCtrl.Bits.FOptsLen = 0;
dudmuck 0:8f0d0ae0a077 1716 fCtrl.Bits.FPending = 0;
dudmuck 0:8f0d0ae0a077 1717 fCtrl.Bits.Ack = false;
dudmuck 0:8f0d0ae0a077 1718 fCtrl.Bits.AdrAckReq = false;
dudmuck 0:8f0d0ae0a077 1719 fCtrl.Bits.Adr = false;
dudmuck 0:8f0d0ae0a077 1720
dudmuck 0:8f0d0ae0a077 1721 // Prepare the frame
dudmuck 0:8f0d0ae0a077 1722 status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
dudmuck 0:8f0d0ae0a077 1723
dudmuck 0:8f0d0ae0a077 1724 // Validate status
dudmuck 0:8f0d0ae0a077 1725 if( status != LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 1726 {
dudmuck 0:8f0d0ae0a077 1727 return status;
dudmuck 0:8f0d0ae0a077 1728 }
dudmuck 0:8f0d0ae0a077 1729
dudmuck 0:8f0d0ae0a077 1730 // Reset confirm parameters
dudmuck 0:8f0d0ae0a077 1731 McpsConfirm.AckReceived = false;
dudmuck 0:8f0d0ae0a077 1732 McpsConfirm.UpLinkCounter = UpLinkCounter;
dudmuck 0:8f0d0ae0a077 1733
dudmuck 25:fed9d5b77183 1734 ScheduleTx();
dudmuck 25:fed9d5b77183 1735
dudmuck 25:fed9d5b77183 1736 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1737 }
dudmuck 0:8f0d0ae0a077 1738
dudmuck 0:8f0d0ae0a077 1739
dudmuck 0:8f0d0ae0a077 1740 static void ResetMacParameters( void )
dudmuck 0:8f0d0ae0a077 1741 {
Wayne Roberts 29:ad409c68c0a6 1742 LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = false;
dudmuck 0:8f0d0ae0a077 1743
dudmuck 0:8f0d0ae0a077 1744 // Counters
dudmuck 0:8f0d0ae0a077 1745 UpLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1746 DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1747
dudmuck 0:8f0d0ae0a077 1748 ChannelsNbRepCounter = 0;
dudmuck 0:8f0d0ae0a077 1749
dudmuck 0:8f0d0ae0a077 1750 MacCommandsBufferIndex = 0;
dudmuck 0:8f0d0ae0a077 1751 MacCommandsBufferToRepeatIndex = 0;
dudmuck 0:8f0d0ae0a077 1752
dudmuck 0:8f0d0ae0a077 1753 IsRxWindowsEnabled = true;
dudmuck 0:8f0d0ae0a077 1754
dudmuck 0:8f0d0ae0a077 1755 LoRaMacParams.ChannelsTxPower = LoRaMacParamsDefaults.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 1756 LoRaMacParams.ChannelsDatarate_fixed = LoRaMacParamsDefaults.ChannelsDatarate_fixed;
dudmuck 0:8f0d0ae0a077 1757
dudmuck 0:8f0d0ae0a077 1758 LoRaMacParams.Rx1DrOffset = LoRaMacParamsDefaults.Rx1DrOffset;
dudmuck 0:8f0d0ae0a077 1759
Wayne Roberts 29:ad409c68c0a6 1760 LoRaMacFlags.Bits.NodeAckRequested = false;
Wayne Roberts 29:ad409c68c0a6 1761 LoRaMacFlags.Bits.SrvAckRequested = false;
dudmuck 0:8f0d0ae0a077 1762 MacCommandsInNextTx = false;
dudmuck 0:8f0d0ae0a077 1763
dudmuck 0:8f0d0ae0a077 1764 // Reset Multicast downlink counters
dudmuck 0:8f0d0ae0a077 1765 MulticastParams_t *cur = MulticastChannels;
dudmuck 0:8f0d0ae0a077 1766 while( cur != NULL )
dudmuck 0:8f0d0ae0a077 1767 {
dudmuck 0:8f0d0ae0a077 1768 cur->DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1769 cur = cur->Next;
dudmuck 0:8f0d0ae0a077 1770 }
dudmuck 0:8f0d0ae0a077 1771
dudmuck 0:8f0d0ae0a077 1772 }
dudmuck 0:8f0d0ae0a077 1773
dudmuck 0:8f0d0ae0a077 1774 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
dudmuck 0:8f0d0ae0a077 1775 {
dudmuck 0:8f0d0ae0a077 1776 uint16_t i;
dudmuck 0:8f0d0ae0a077 1777 uint32_t mic = 0;
dudmuck 0:8f0d0ae0a077 1778 const void* payload = fBuffer;
dudmuck 0:8f0d0ae0a077 1779 uint8_t framePort = fPort;
Wayne Roberts 29:ad409c68c0a6 1780 uint8_t LoRaMacTxPayloadLen = 0;
Wayne Roberts 29:ad409c68c0a6 1781
Wayne Roberts 29:ad409c68c0a6 1782 LoRaMacFlags.Bits.NodeAckRequested = false;
Wayne Roberts 29:ad409c68c0a6 1783 tx_buf_len = 0;
dudmuck 0:8f0d0ae0a077 1784
dudmuck 0:8f0d0ae0a077 1785 if( fBuffer == NULL )
dudmuck 0:8f0d0ae0a077 1786 {
dudmuck 0:8f0d0ae0a077 1787 fBufferSize = 0;
dudmuck 0:8f0d0ae0a077 1788 }
dudmuck 0:8f0d0ae0a077 1789
dudmuck 0:8f0d0ae0a077 1790 LoRaMacTxPayloadLen = fBufferSize;
dudmuck 0:8f0d0ae0a077 1791
Wayne Roberts 29:ad409c68c0a6 1792 Radio::radio.tx_buf[tx_buf_len++] = macHdr->Value;
dudmuck 0:8f0d0ae0a077 1793
dudmuck 0:8f0d0ae0a077 1794 switch( macHdr->Bits.MType )
dudmuck 0:8f0d0ae0a077 1795 {
dudmuck 0:8f0d0ae0a077 1796 case FRAME_TYPE_JOIN_REQ:
Wayne Roberts 29:ad409c68c0a6 1797 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacAppEui, 8 );
Wayne Roberts 29:ad409c68c0a6 1798 tx_buf_len += 8;
Wayne Roberts 29:ad409c68c0a6 1799 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
Wayne Roberts 29:ad409c68c0a6 1800 tx_buf_len += 8;
Wayne Roberts 29:ad409c68c0a6 1801
Wayne Roberts 29:ad409c68c0a6 1802 LoRaMacDevNonce = Radio::Random( );
Wayne Roberts 29:ad409c68c0a6 1803
Wayne Roberts 29:ad409c68c0a6 1804 Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1805 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1806
Wayne Roberts 29:ad409c68c0a6 1807 LoRaMacJoinComputeMic( Radio::radio.tx_buf, tx_buf_len & 0xFF, LoRaMacAppKey, &mic );
Wayne Roberts 29:ad409c68c0a6 1808
Wayne Roberts 29:ad409c68c0a6 1809 Radio::radio.tx_buf[tx_buf_len++] = mic & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1810 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 8 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1811 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 16 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1812 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 24 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 1813
dudmuck 0:8f0d0ae0a077 1814 break;
dudmuck 0:8f0d0ae0a077 1815 case FRAME_TYPE_DATA_CONFIRMED_UP:
Wayne Roberts 29:ad409c68c0a6 1816 LoRaMacFlags.Bits.NodeAckRequested = true;
dudmuck 0:8f0d0ae0a077 1817 //Intentional fallthrough
dudmuck 0:8f0d0ae0a077 1818 case FRAME_TYPE_DATA_UNCONFIRMED_UP:
Wayne Roberts 29:ad409c68c0a6 1819 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
dudmuck 0:8f0d0ae0a077 1820 {
dudmuck 0:8f0d0ae0a077 1821 return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet
dudmuck 0:8f0d0ae0a077 1822 }
dudmuck 0:8f0d0ae0a077 1823
dudmuck 0:8f0d0ae0a077 1824 fCtrl->Bits.AdrAckReq = 0;
dudmuck 0:8f0d0ae0a077 1825
Wayne Roberts 29:ad409c68c0a6 1826 if( LoRaMacFlags.Bits.SrvAckRequested == true )
dudmuck 0:8f0d0ae0a077 1827 {
Wayne Roberts 29:ad409c68c0a6 1828 LoRaMacFlags.Bits.SrvAckRequested = false;
dudmuck 0:8f0d0ae0a077 1829 fCtrl->Bits.Ack = 1;
dudmuck 0:8f0d0ae0a077 1830 }
dudmuck 0:8f0d0ae0a077 1831
Wayne Roberts 29:ad409c68c0a6 1832 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1833 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1834 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1835 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1836
Wayne Roberts 29:ad409c68c0a6 1837 Radio::radio.tx_buf[tx_buf_len++] = fCtrl->Value;
Wayne Roberts 29:ad409c68c0a6 1838
Wayne Roberts 29:ad409c68c0a6 1839 Radio::radio.tx_buf[tx_buf_len++] = UpLinkCounter & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1840 Radio::radio.tx_buf[tx_buf_len++] = ( UpLinkCounter >> 8 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 1841
dudmuck 0:8f0d0ae0a077 1842 // Copy the MAC commands which must be re-send into the MAC command buffer
dudmuck 0:8f0d0ae0a077 1843 memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex );
dudmuck 0:8f0d0ae0a077 1844 MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex;
dudmuck 0:8f0d0ae0a077 1845
dudmuck 0:8f0d0ae0a077 1846 if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
dudmuck 0:8f0d0ae0a077 1847 {
dudmuck 0:8f0d0ae0a077 1848 if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) )
dudmuck 0:8f0d0ae0a077 1849 {
dudmuck 0:8f0d0ae0a077 1850 fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
dudmuck 0:8f0d0ae0a077 1851
dudmuck 0:8f0d0ae0a077 1852 // Update FCtrl field with new value of OptionsLength
Wayne Roberts 29:ad409c68c0a6 1853 Radio::radio.tx_buf[0x05] = fCtrl->Value;
dudmuck 0:8f0d0ae0a077 1854 for( i = 0; i < MacCommandsBufferIndex; i++ )
dudmuck 0:8f0d0ae0a077 1855 {
Wayne Roberts 29:ad409c68c0a6 1856 Radio::radio.tx_buf[tx_buf_len++] = MacCommandsBuffer[i];
dudmuck 0:8f0d0ae0a077 1857 }
dudmuck 0:8f0d0ae0a077 1858 }
dudmuck 0:8f0d0ae0a077 1859 }
dudmuck 0:8f0d0ae0a077 1860 else
dudmuck 0:8f0d0ae0a077 1861 {
dudmuck 0:8f0d0ae0a077 1862 if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) )
dudmuck 0:8f0d0ae0a077 1863 {
dudmuck 0:8f0d0ae0a077 1864 LoRaMacTxPayloadLen = MacCommandsBufferIndex;
dudmuck 0:8f0d0ae0a077 1865 payload = MacCommandsBuffer;
dudmuck 0:8f0d0ae0a077 1866 framePort = 0;
dudmuck 0:8f0d0ae0a077 1867 }
dudmuck 0:8f0d0ae0a077 1868 }
dudmuck 0:8f0d0ae0a077 1869 MacCommandsInNextTx = false;
dudmuck 0:8f0d0ae0a077 1870 // Store MAC commands which must be re-send in case the device does not receive a downlink anymore
dudmuck 0:8f0d0ae0a077 1871 MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat( MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat );
dudmuck 0:8f0d0ae0a077 1872 if( MacCommandsBufferToRepeatIndex > 0 )
dudmuck 0:8f0d0ae0a077 1873 {
dudmuck 0:8f0d0ae0a077 1874 MacCommandsInNextTx = true;
dudmuck 0:8f0d0ae0a077 1875 }
dudmuck 0:8f0d0ae0a077 1876
dudmuck 0:8f0d0ae0a077 1877 if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
dudmuck 0:8f0d0ae0a077 1878 {
Wayne Roberts 29:ad409c68c0a6 1879 Radio::radio.tx_buf[tx_buf_len++] = framePort;
dudmuck 0:8f0d0ae0a077 1880
dudmuck 0:8f0d0ae0a077 1881 if( framePort == 0 )
dudmuck 0:8f0d0ae0a077 1882 {
Wayne Roberts 29:ad409c68c0a6 1883 LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &Radio::radio.tx_buf[tx_buf_len] );
dudmuck 0:8f0d0ae0a077 1884 }
dudmuck 0:8f0d0ae0a077 1885 else
dudmuck 0:8f0d0ae0a077 1886 {
Wayne Roberts 29:ad409c68c0a6 1887 LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &Radio::radio.tx_buf[tx_buf_len] );
dudmuck 0:8f0d0ae0a077 1888 }
dudmuck 0:8f0d0ae0a077 1889 }
Wayne Roberts 29:ad409c68c0a6 1890 tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
Wayne Roberts 29:ad409c68c0a6 1891
Wayne Roberts 29:ad409c68c0a6 1892 LoRaMacComputeMic( Radio::radio.tx_buf, tx_buf_len, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic );
Wayne Roberts 29:ad409c68c0a6 1893
Wayne Roberts 29:ad409c68c0a6 1894 Radio::radio.tx_buf[tx_buf_len + 0] = mic & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1895 Radio::radio.tx_buf[tx_buf_len + 1] = ( mic >> 8 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1896 Radio::radio.tx_buf[tx_buf_len + 2] = ( mic >> 16 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1897 Radio::radio.tx_buf[tx_buf_len + 3] = ( mic >> 24 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1898
Wayne Roberts 29:ad409c68c0a6 1899 tx_buf_len += LORAMAC_MFR_LEN;
dudmuck 0:8f0d0ae0a077 1900
dudmuck 0:8f0d0ae0a077 1901 break;
dudmuck 0:8f0d0ae0a077 1902 case FRAME_TYPE_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 1903 if( ( fBuffer != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
dudmuck 0:8f0d0ae0a077 1904 {
Wayne Roberts 29:ad409c68c0a6 1905 memcpy1( Radio::radio.tx_buf + tx_buf_len, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen );
Wayne Roberts 29:ad409c68c0a6 1906 tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
dudmuck 0:8f0d0ae0a077 1907 }
dudmuck 0:8f0d0ae0a077 1908 break;
dudmuck 0:8f0d0ae0a077 1909 default:
dudmuck 0:8f0d0ae0a077 1910 return LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 1911 }
dudmuck 0:8f0d0ae0a077 1912
dudmuck 0:8f0d0ae0a077 1913 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1914 }
dudmuck 0:8f0d0ae0a077 1915
dudmuck 0:8f0d0ae0a077 1916
dudmuck 0:8f0d0ae0a077 1917 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout )
dudmuck 0:8f0d0ae0a077 1918 {
dudmuck 0:8f0d0ae0a077 1919 int8_t txPowerIndex = 0;
dudmuck 0:8f0d0ae0a077 1920 int8_t txPower = 0;
dudmuck 0:8f0d0ae0a077 1921
dudmuck 0:8f0d0ae0a077 1922 txPowerIndex = LoRaMacParams.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 1923 txPower = TxPowers[txPowerIndex];
Wayne Roberts 29:ad409c68c0a6 1924 Radio::SetTxContinuousWave( Channels[Channel].Frequency, txPower, timeout );
dudmuck 0:8f0d0ae0a077 1925
dudmuck 0:8f0d0ae0a077 1926 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1927 }
dudmuck 0:8f0d0ae0a077 1928
dudmuck 0:8f0d0ae0a077 1929 LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power )
dudmuck 0:8f0d0ae0a077 1930 {
Wayne Roberts 29:ad409c68c0a6 1931 Radio::SetTxContinuousWave( frequency, power, timeout );
dudmuck 0:8f0d0ae0a077 1932
dudmuck 0:8f0d0ae0a077 1933 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1934 }
dudmuck 0:8f0d0ae0a077 1935
dudmuck 0:8f0d0ae0a077 1936 void seconds()
dudmuck 0:8f0d0ae0a077 1937 {
Wayne Roberts 29:ad409c68c0a6 1938 mac_printf("second\r\n");
Wayne Roberts 29:ad409c68c0a6 1939 }
Wayne Roberts 29:ad409c68c0a6 1940
Wayne Roberts 34:9c8966cd66a2 1941 void on_dio0_top_half()
Wayne Roberts 29:ad409c68c0a6 1942 {
dudmuck 0:8f0d0ae0a077 1943 }
dudmuck 0:8f0d0ae0a077 1944
Wayne Roberts 29:ad409c68c0a6 1945 unsigned get_symbol_period_us(uint8_t sf)
Wayne Roberts 29:ad409c68c0a6 1946 {
Wayne Roberts 29:ad409c68c0a6 1947 float bwMHz = LORA_BANDWIDTH_KHZ / 1000.0;
Wayne Roberts 29:ad409c68c0a6 1948 // return symbol period in microseconds
Wayne Roberts 29:ad409c68c0a6 1949 return (1 << sf) / bwMHz;
Wayne Roberts 29:ad409c68c0a6 1950 }
Wayne Roberts 29:ad409c68c0a6 1951
Wayne Roberts 29:ad409c68c0a6 1952 const RadioEvents_t rev = {
Wayne Roberts 29:ad409c68c0a6 1953 /* Dio0_top_half */ on_dio0_top_half,
Wayne Roberts 33:bc0b6be19e07 1954 /* TxDone_topHalf */ OnRadioTxDone_topHalf,
Wayne Roberts 29:ad409c68c0a6 1955 /* TxDone_botHalf */ OnRadioTxDone_bh,
Wayne Roberts 29:ad409c68c0a6 1956 /* TxTimeout */ OnRadioTxTimeout,
Wayne Roberts 29:ad409c68c0a6 1957 /* RxDone */ OnRadioRxDone,
Wayne Roberts 29:ad409c68c0a6 1958 /* RxTimeout */ OnRadioRxTimeout,
Wayne Roberts 29:ad409c68c0a6 1959 /* RxError */ OnRadioRxError,
Wayne Roberts 29:ad409c68c0a6 1960 /* FhssChangeChannel */NULL,
Wayne Roberts 29:ad409c68c0a6 1961 /* CadDone */ NULL
Wayne Roberts 29:ad409c68c0a6 1962 };
Wayne Roberts 29:ad409c68c0a6 1963
Wayne Roberts 34:9c8966cd66a2 1964 osThreadId_t tid_main;
Wayne Roberts 34:9c8966cd66a2 1965
Wayne Roberts 34:9c8966cd66a2 1966 void sleep_test_callback()
Wayne Roberts 34:9c8966cd66a2 1967 {
Wayne Roberts 34:9c8966cd66a2 1968 txDoneAt = LowPowerClock::now();
Wayne Roberts 34:9c8966cd66a2 1969 osThreadFlagsSet(tid_main, 1);
Wayne Roberts 34:9c8966cd66a2 1970 }
Wayne Roberts 34:9c8966cd66a2 1971
dudmuck 0:8f0d0ae0a077 1972 LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks )
dudmuck 0:8f0d0ae0a077 1973 {
Wayne Roberts 34:9c8966cd66a2 1974 if (primitives == NULL)
dudmuck 0:8f0d0ae0a077 1975 {
dudmuck 0:8f0d0ae0a077 1976 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 1977 }
dudmuck 0:8f0d0ae0a077 1978
dudmuck 0:8f0d0ae0a077 1979 if( ( primitives->MacMcpsConfirm == NULL ) ||
dudmuck 0:8f0d0ae0a077 1980 ( primitives->MacMcpsIndication == NULL ) ||
dudmuck 0:8f0d0ae0a077 1981 ( primitives->MacMlmeConfirm == NULL ) )
dudmuck 0:8f0d0ae0a077 1982 {
dudmuck 0:8f0d0ae0a077 1983 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 1984 }
dudmuck 0:8f0d0ae0a077 1985
dudmuck 0:8f0d0ae0a077 1986 LoRaMacPrimitives = primitives;
dudmuck 0:8f0d0ae0a077 1987 LoRaMacCallbacks = callbacks;
dudmuck 0:8f0d0ae0a077 1988
dudmuck 0:8f0d0ae0a077 1989 LoRaMacFlags.Value = 0;
dudmuck 0:8f0d0ae0a077 1990
dudmuck 0:8f0d0ae0a077 1991 JoinRequestTrials = 0;
dudmuck 0:8f0d0ae0a077 1992 MaxJoinRequestTrials = 255;
dudmuck 0:8f0d0ae0a077 1993
Wayne Roberts 29:ad409c68c0a6 1994 BeaconCtx.symbol_period_us = get_symbol_period_us(Datarates[LORAMAC_DEFAULT_DATARATE]);
dudmuck 0:8f0d0ae0a077 1995
dudmuck 0:8f0d0ae0a077 1996 // Reset to defaults
dudmuck 0:8f0d0ae0a077 1997 LoRaMacParamsDefaults.ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
dudmuck 0:8f0d0ae0a077 1998 LoRaMacParamsDefaults.ChannelsDatarate_fixed = LORAMAC_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 1999
Wayne Roberts 29:ad409c68c0a6 2000 LoRaMacParamsDefaults.SystemMaxRxError_ms = 20;
Wayne Roberts 29:ad409c68c0a6 2001 LoRaMacParamsDefaults.MinRxSymbols = (LoRaMacParamsDefaults.SystemMaxRxError_ms * 1000) / BeaconCtx.symbol_period_us;
Wayne Roberts 29:ad409c68c0a6 2002 if (LoRaMacParamsDefaults.MinRxSymbols < MIN_SYMBOL_TIMEOUT)
Wayne Roberts 29:ad409c68c0a6 2003 LoRaMacParamsDefaults.MinRxSymbols = MIN_SYMBOL_TIMEOUT;
Wayne Roberts 29:ad409c68c0a6 2004
dudmuck 0:8f0d0ae0a077 2005 LoRaMacParamsDefaults.MaxRxWindow = MAX_RX_WINDOW;
dudmuck 0:8f0d0ae0a077 2006
dudmuck 0:8f0d0ae0a077 2007 LoRaMacParamsDefaults.ReceiveDelay_us = RECEIVE_DELAY_us;
dudmuck 0:8f0d0ae0a077 2008 LoRaMacParamsDefaults.JoinAcceptDelay_us = JOIN_ACCEPT_DELAY_us;
dudmuck 0:8f0d0ae0a077 2009
dudmuck 0:8f0d0ae0a077 2010 LoRaMacParamsDefaults.ChannelsNbRep = 1;
dudmuck 0:8f0d0ae0a077 2011 LoRaMacParamsDefaults.Rx1DrOffset = 0;
dudmuck 0:8f0d0ae0a077 2012
dudmuck 0:8f0d0ae0a077 2013 for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
dudmuck 0:8f0d0ae0a077 2014 {
dudmuck 0:8f0d0ae0a077 2015 Channels[i].Frequency = LORAMAC_FIRST_CHANNEL + (i * LORAMAC_STEPWIDTH_CHANNEL);
dudmuck 18:9ac71c0eb70d 2016 Channels[i].DrRange.Value = (LORAMAC_MAX_DATARATE << 4) | LORAMAC_MIN_DATARATE;
dudmuck 0:8f0d0ae0a077 2017 Channels[i].Band = 0;
dudmuck 0:8f0d0ae0a077 2018 }
dudmuck 0:8f0d0ae0a077 2019
dudmuck 0:8f0d0ae0a077 2020 // Init parameters which are not set in function ResetMacParameters
Wayne Roberts 29:ad409c68c0a6 2021 LoRaMacParams.SystemMaxRxError_ms = LoRaMacParamsDefaults.SystemMaxRxError_ms;
dudmuck 0:8f0d0ae0a077 2022 LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols;
dudmuck 0:8f0d0ae0a077 2023 LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow;
dudmuck 0:8f0d0ae0a077 2024 LoRaMacParams.ReceiveDelay_us = LoRaMacParamsDefaults.ReceiveDelay_us;
dudmuck 0:8f0d0ae0a077 2025 LoRaMacParams.JoinAcceptDelay_us = LoRaMacParamsDefaults.JoinAcceptDelay_us;
dudmuck 0:8f0d0ae0a077 2026 LoRaMacParams.ChannelsNbRep = LoRaMacParamsDefaults.ChannelsNbRep;
dudmuck 0:8f0d0ae0a077 2027
dudmuck 0:8f0d0ae0a077 2028 ResetMacParameters( );
Wayne Roberts 34:9c8966cd66a2 2029 if (LoRaMacCryptoInit() < 0) {
Wayne Roberts 34:9c8966cd66a2 2030 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 34:9c8966cd66a2 2031 }
dudmuck 0:8f0d0ae0a077 2032
dudmuck 0:8f0d0ae0a077 2033 // Initialize Radio driver
Wayne Roberts 29:ad409c68c0a6 2034 Radio::Init(&rev);
Wayne Roberts 34:9c8966cd66a2 2035
Wayne Roberts 34:9c8966cd66a2 2036 {
Wayne Roberts 34:9c8966cd66a2 2037 unsigned sum = 0;
Wayne Roberts 34:9c8966cd66a2 2038 sleep_manager_unlock_deep_sleep();
Wayne Roberts 34:9c8966cd66a2 2039 tid_main = ThisThread::get_id();
Wayne Roberts 34:9c8966cd66a2 2040 /*** How long this MCU takes to wake up from deep-sleep ***/
Wayne Roberts 34:9c8966cd66a2 2041 for (unsigned n = 0; n < 16; n++) {
Wayne Roberts 34:9c8966cd66a2 2042 long end, start;
Wayne Roberts 34:9c8966cd66a2 2043 txDoneAt = LowPowerClock::now();
Wayne Roberts 34:9c8966cd66a2 2044 start = txDoneAt.time_since_epoch().count();
Wayne Roberts 34:9c8966cd66a2 2045
Wayne Roberts 34:9c8966cd66a2 2046 LoRaMacFlags.Value = 0;
Wayne Roberts 34:9c8966cd66a2 2047 rx_timeout.attach(sleep_test_callback, 10ms);
Wayne Roberts 34:9c8966cd66a2 2048 ThisThread::flags_wait_any(1);
Wayne Roberts 34:9c8966cd66a2 2049 end = LowPowerClock::now().time_since_epoch().count();
Wayne Roberts 34:9c8966cd66a2 2050 sum += (end - start) - 10000;
Wayne Roberts 34:9c8966cd66a2 2051 }
Wayne Roberts 34:9c8966cd66a2 2052 LoRaMacFlags.Value = 0;
Wayne Roberts 34:9c8966cd66a2 2053 sum >>= 4; // 16 samples = 2^4
Wayne Roberts 34:9c8966cd66a2 2054 printf("mcu takes %uus to wake up\r\n", sum);
Wayne Roberts 34:9c8966cd66a2 2055 mcu_wakeup_latency = microseconds(sum);
Wayne Roberts 34:9c8966cd66a2 2056 }
dudmuck 0:8f0d0ae0a077 2057
dudmuck 0:8f0d0ae0a077 2058 // Random seed initialization
Wayne Roberts 29:ad409c68c0a6 2059 srand1( Radio::Random( ) );
dudmuck 0:8f0d0ae0a077 2060
dudmuck 0:8f0d0ae0a077 2061 PublicNetwork = true;
Wayne Roberts 29:ad409c68c0a6 2062 Radio::SetPublicNetwork( PublicNetwork );
Wayne Roberts 29:ad409c68c0a6 2063 Radio::Sleep( );
Wayne Roberts 29:ad409c68c0a6 2064
Wayne Roberts 29:ad409c68c0a6 2065 RxWindowsParam = ComputeRxWindowParameters(LORAMAC_DEFAULT_DATARATE, LoRaMacParams.SystemMaxRxError_ms);
dudmuck 0:8f0d0ae0a077 2066
dudmuck 0:8f0d0ae0a077 2067 return LORAMAC_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 2068 } // ..LoRaMacInitialization()
dudmuck 0:8f0d0ae0a077 2069
dudmuck 0:8f0d0ae0a077 2070 LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
dudmuck 0:8f0d0ae0a077 2071 {
dudmuck 0:8f0d0ae0a077 2072 uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
dudmuck 0:8f0d0ae0a077 2073
dudmuck 0:8f0d0ae0a077 2074 if( txInfo == NULL )
dudmuck 0:8f0d0ae0a077 2075 {
dudmuck 0:8f0d0ae0a077 2076 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2077 }
dudmuck 0:8f0d0ae0a077 2078
Wayne Roberts 29:ad409c68c0a6 2079 txInfo->CurrentPayloadSize = LORAMAC_PHY_MAXPAYLOAD;
dudmuck 0:8f0d0ae0a077 2080
dudmuck 0:8f0d0ae0a077 2081 if( txInfo->CurrentPayloadSize >= fOptLen )
dudmuck 0:8f0d0ae0a077 2082 {
dudmuck 0:8f0d0ae0a077 2083 txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen;
dudmuck 0:8f0d0ae0a077 2084 }
dudmuck 0:8f0d0ae0a077 2085 else
dudmuck 0:8f0d0ae0a077 2086 {
dudmuck 0:8f0d0ae0a077 2087 return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
dudmuck 0:8f0d0ae0a077 2088 }
dudmuck 0:8f0d0ae0a077 2089
dudmuck 0:8f0d0ae0a077 2090 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2091 }
dudmuck 0:8f0d0ae0a077 2092
dudmuck 0:8f0d0ae0a077 2093 LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
dudmuck 0:8f0d0ae0a077 2094 {
dudmuck 0:8f0d0ae0a077 2095 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2096
dudmuck 0:8f0d0ae0a077 2097 if( mibGet == NULL )
dudmuck 0:8f0d0ae0a077 2098 {
dudmuck 0:8f0d0ae0a077 2099 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2100 }
dudmuck 0:8f0d0ae0a077 2101
dudmuck 0:8f0d0ae0a077 2102 switch( mibGet->Type )
dudmuck 0:8f0d0ae0a077 2103 {
dudmuck 0:8f0d0ae0a077 2104 case MIB_NETWORK_JOINED:
dudmuck 0:8f0d0ae0a077 2105 {
Wayne Roberts 29:ad409c68c0a6 2106 mibGet->Param.IsNetworkJoined = LoRaMacFlags.Bits.IsLoRaMacNetworkJoined;
dudmuck 0:8f0d0ae0a077 2107 break;
dudmuck 0:8f0d0ae0a077 2108 }
dudmuck 0:8f0d0ae0a077 2109 case MIB_NET_ID:
dudmuck 0:8f0d0ae0a077 2110 {
dudmuck 0:8f0d0ae0a077 2111 mibGet->Param.NetID = LoRaMacNetID;
dudmuck 0:8f0d0ae0a077 2112 break;
dudmuck 0:8f0d0ae0a077 2113 }
dudmuck 0:8f0d0ae0a077 2114 case MIB_DEV_ADDR:
dudmuck 0:8f0d0ae0a077 2115 {
dudmuck 0:8f0d0ae0a077 2116 mibGet->Param.DevAddr = LoRaMacDevAddr;
dudmuck 0:8f0d0ae0a077 2117 break;
dudmuck 0:8f0d0ae0a077 2118 }
dudmuck 0:8f0d0ae0a077 2119 case MIB_NWK_SKEY:
dudmuck 0:8f0d0ae0a077 2120 {
dudmuck 0:8f0d0ae0a077 2121 mibGet->Param.NwkSKey = LoRaMacNwkSKey;
dudmuck 0:8f0d0ae0a077 2122 break;
dudmuck 0:8f0d0ae0a077 2123 }
dudmuck 0:8f0d0ae0a077 2124 case MIB_APP_SKEY:
dudmuck 0:8f0d0ae0a077 2125 {
dudmuck 0:8f0d0ae0a077 2126 mibGet->Param.AppSKey = LoRaMacAppSKey;
dudmuck 0:8f0d0ae0a077 2127 break;
dudmuck 0:8f0d0ae0a077 2128 }
dudmuck 0:8f0d0ae0a077 2129 case MIB_PUBLIC_NETWORK:
dudmuck 0:8f0d0ae0a077 2130 {
dudmuck 0:8f0d0ae0a077 2131 mibGet->Param.EnablePublicNetwork = PublicNetwork;
dudmuck 0:8f0d0ae0a077 2132 break;
dudmuck 0:8f0d0ae0a077 2133 }
dudmuck 0:8f0d0ae0a077 2134 case MIB_CHANNELS_NB_REP:
dudmuck 0:8f0d0ae0a077 2135 {
dudmuck 0:8f0d0ae0a077 2136 mibGet->Param.ChannelNbRep = LoRaMacParams.ChannelsNbRep;
dudmuck 0:8f0d0ae0a077 2137 break;
dudmuck 0:8f0d0ae0a077 2138 }
dudmuck 0:8f0d0ae0a077 2139 case MIB_MAX_RX_WINDOW_DURATION:
dudmuck 0:8f0d0ae0a077 2140 {
dudmuck 0:8f0d0ae0a077 2141 mibGet->Param.MaxRxWindow = LoRaMacParams.MaxRxWindow;
dudmuck 0:8f0d0ae0a077 2142 break;
dudmuck 0:8f0d0ae0a077 2143 }
dudmuck 0:8f0d0ae0a077 2144 case MIB_CHANNELS_DEFAULT_TX_POWER:
dudmuck 0:8f0d0ae0a077 2145 {
dudmuck 0:8f0d0ae0a077 2146 mibGet->Param.ChannelsDefaultTxPower = LoRaMacParamsDefaults.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 2147 break;
dudmuck 0:8f0d0ae0a077 2148 }
dudmuck 0:8f0d0ae0a077 2149 case MIB_CHANNELS_TX_POWER:
dudmuck 0:8f0d0ae0a077 2150 {
dudmuck 0:8f0d0ae0a077 2151 mibGet->Param.ChannelsTxPower = LoRaMacParams.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 2152 break;
dudmuck 0:8f0d0ae0a077 2153 }
dudmuck 0:8f0d0ae0a077 2154 case MIB_UPLINK_COUNTER:
dudmuck 0:8f0d0ae0a077 2155 {
dudmuck 0:8f0d0ae0a077 2156 mibGet->Param.UpLinkCounter = UpLinkCounter;
dudmuck 0:8f0d0ae0a077 2157 break;
dudmuck 0:8f0d0ae0a077 2158 }
dudmuck 0:8f0d0ae0a077 2159 case MIB_DOWNLINK_COUNTER:
dudmuck 0:8f0d0ae0a077 2160 {
dudmuck 0:8f0d0ae0a077 2161 mibGet->Param.DownLinkCounter = DownLinkCounter;
dudmuck 0:8f0d0ae0a077 2162 break;
dudmuck 0:8f0d0ae0a077 2163 }
dudmuck 0:8f0d0ae0a077 2164 case MIB_MULTICAST_CHANNEL:
dudmuck 0:8f0d0ae0a077 2165 {
dudmuck 0:8f0d0ae0a077 2166 mibGet->Param.MulticastList = MulticastChannels;
dudmuck 0:8f0d0ae0a077 2167 break;
dudmuck 0:8f0d0ae0a077 2168 }
dudmuck 0:8f0d0ae0a077 2169 case MIB_SYSTEM_MAX_RX_ERROR:
dudmuck 0:8f0d0ae0a077 2170 {
Wayne Roberts 29:ad409c68c0a6 2171 mibGet->Param.SystemMaxRxError_ms = LoRaMacParams.SystemMaxRxError_ms;
dudmuck 0:8f0d0ae0a077 2172 break;
dudmuck 0:8f0d0ae0a077 2173 }
dudmuck 0:8f0d0ae0a077 2174 case MIB_MIN_RX_SYMBOLS:
dudmuck 0:8f0d0ae0a077 2175 {
dudmuck 0:8f0d0ae0a077 2176 mibGet->Param.MinRxSymbols = LoRaMacParams.MinRxSymbols;
dudmuck 0:8f0d0ae0a077 2177 break;
dudmuck 0:8f0d0ae0a077 2178 }
dudmuck 0:8f0d0ae0a077 2179 default:
dudmuck 0:8f0d0ae0a077 2180 status = LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 2181 break;
dudmuck 0:8f0d0ae0a077 2182 }
dudmuck 0:8f0d0ae0a077 2183
dudmuck 0:8f0d0ae0a077 2184 return status;
dudmuck 0:8f0d0ae0a077 2185 }
dudmuck 0:8f0d0ae0a077 2186
dudmuck 0:8f0d0ae0a077 2187 LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
dudmuck 0:8f0d0ae0a077 2188 {
dudmuck 0:8f0d0ae0a077 2189 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2190
dudmuck 0:8f0d0ae0a077 2191 if( mibSet == NULL )
dudmuck 0:8f0d0ae0a077 2192 {
dudmuck 0:8f0d0ae0a077 2193 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2194 }
dudmuck 0:8f0d0ae0a077 2195
dudmuck 0:8f0d0ae0a077 2196 switch( mibSet->Type )
dudmuck 0:8f0d0ae0a077 2197 {
dudmuck 0:8f0d0ae0a077 2198 case MIB_NETWORK_JOINED:
dudmuck 0:8f0d0ae0a077 2199 {
Wayne Roberts 29:ad409c68c0a6 2200 LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined;
Wayne Roberts 29:ad409c68c0a6 2201 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) {
Wayne Roberts 29:ad409c68c0a6 2202 mac_printf("beaconDetach\r\n");
Wayne Roberts 34:9c8966cd66a2 2203 BeaconCtx.timeout_rx.detach();
Wayne Roberts 34:9c8966cd66a2 2204 BeaconCtx.timeout_guard.detach();
dudmuck 16:915815632c1f 2205 BeaconCtx.state = BEACON_STATE_NONE;
dudmuck 16:915815632c1f 2206 }
dudmuck 0:8f0d0ae0a077 2207 break;
dudmuck 0:8f0d0ae0a077 2208 }
dudmuck 0:8f0d0ae0a077 2209 case MIB_NET_ID:
dudmuck 0:8f0d0ae0a077 2210 {
dudmuck 0:8f0d0ae0a077 2211 LoRaMacNetID = mibSet->Param.NetID;
dudmuck 0:8f0d0ae0a077 2212 break;
dudmuck 0:8f0d0ae0a077 2213 }
dudmuck 0:8f0d0ae0a077 2214 case MIB_DEV_ADDR:
dudmuck 0:8f0d0ae0a077 2215 {
dudmuck 0:8f0d0ae0a077 2216 LoRaMacDevAddr = mibSet->Param.DevAddr;
dudmuck 0:8f0d0ae0a077 2217 break;
dudmuck 0:8f0d0ae0a077 2218 }
dudmuck 0:8f0d0ae0a077 2219 case MIB_NWK_SKEY:
dudmuck 0:8f0d0ae0a077 2220 {
dudmuck 0:8f0d0ae0a077 2221 if( mibSet->Param.NwkSKey != NULL )
dudmuck 0:8f0d0ae0a077 2222 {
dudmuck 0:8f0d0ae0a077 2223 memcpy1( LoRaMacNwkSKey, mibSet->Param.NwkSKey,
dudmuck 0:8f0d0ae0a077 2224 sizeof( LoRaMacNwkSKey ) );
dudmuck 0:8f0d0ae0a077 2225 }
dudmuck 0:8f0d0ae0a077 2226 else
dudmuck 0:8f0d0ae0a077 2227 {
dudmuck 0:8f0d0ae0a077 2228 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2229 }
dudmuck 0:8f0d0ae0a077 2230 break;
dudmuck 0:8f0d0ae0a077 2231 }
dudmuck 0:8f0d0ae0a077 2232 case MIB_APP_SKEY:
dudmuck 0:8f0d0ae0a077 2233 {
dudmuck 0:8f0d0ae0a077 2234 if( mibSet->Param.AppSKey != NULL )
dudmuck 0:8f0d0ae0a077 2235 {
dudmuck 0:8f0d0ae0a077 2236 memcpy1( LoRaMacAppSKey, mibSet->Param.AppSKey,
dudmuck 0:8f0d0ae0a077 2237 sizeof( LoRaMacAppSKey ) );
dudmuck 0:8f0d0ae0a077 2238 }
dudmuck 0:8f0d0ae0a077 2239 else
dudmuck 0:8f0d0ae0a077 2240 {
dudmuck 0:8f0d0ae0a077 2241 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2242 }
dudmuck 0:8f0d0ae0a077 2243 break;
dudmuck 0:8f0d0ae0a077 2244 }
dudmuck 0:8f0d0ae0a077 2245 case MIB_PUBLIC_NETWORK:
dudmuck 0:8f0d0ae0a077 2246 {
dudmuck 0:8f0d0ae0a077 2247 PublicNetwork = mibSet->Param.EnablePublicNetwork;
Wayne Roberts 29:ad409c68c0a6 2248 Radio::SetPublicNetwork( PublicNetwork );
dudmuck 0:8f0d0ae0a077 2249 break;
dudmuck 0:8f0d0ae0a077 2250 }
dudmuck 0:8f0d0ae0a077 2251 case MIB_CHANNELS_NB_REP:
dudmuck 0:8f0d0ae0a077 2252 {
dudmuck 0:8f0d0ae0a077 2253 if( ( mibSet->Param.ChannelNbRep >= 1 ) &&
dudmuck 0:8f0d0ae0a077 2254 ( mibSet->Param.ChannelNbRep <= 15 ) )
dudmuck 0:8f0d0ae0a077 2255 {
dudmuck 0:8f0d0ae0a077 2256 LoRaMacParams.ChannelsNbRep = mibSet->Param.ChannelNbRep;
dudmuck 0:8f0d0ae0a077 2257 }
dudmuck 0:8f0d0ae0a077 2258 else
dudmuck 0:8f0d0ae0a077 2259 {
dudmuck 0:8f0d0ae0a077 2260 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2261 }
dudmuck 0:8f0d0ae0a077 2262 break;
dudmuck 0:8f0d0ae0a077 2263 }
dudmuck 0:8f0d0ae0a077 2264 case MIB_MAX_RX_WINDOW_DURATION:
dudmuck 0:8f0d0ae0a077 2265 {
dudmuck 0:8f0d0ae0a077 2266 LoRaMacParams.MaxRxWindow = mibSet->Param.MaxRxWindow;
dudmuck 0:8f0d0ae0a077 2267 break;
dudmuck 0:8f0d0ae0a077 2268 }
dudmuck 0:8f0d0ae0a077 2269 case MIB_CHANNELS_DEFAULT_TX_POWER:
dudmuck 0:8f0d0ae0a077 2270 {
dudmuck 0:8f0d0ae0a077 2271 if( ValueInRange( mibSet->Param.ChannelsDefaultTxPower,
dudmuck 0:8f0d0ae0a077 2272 LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
dudmuck 0:8f0d0ae0a077 2273 {
dudmuck 0:8f0d0ae0a077 2274 LoRaMacParamsDefaults.ChannelsTxPower = mibSet->Param.ChannelsDefaultTxPower;
dudmuck 0:8f0d0ae0a077 2275 }
dudmuck 0:8f0d0ae0a077 2276 else
dudmuck 0:8f0d0ae0a077 2277 {
dudmuck 0:8f0d0ae0a077 2278 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2279 }
dudmuck 0:8f0d0ae0a077 2280 break;
dudmuck 0:8f0d0ae0a077 2281 }
dudmuck 0:8f0d0ae0a077 2282 case MIB_CHANNELS_TX_POWER:
dudmuck 0:8f0d0ae0a077 2283 {
dudmuck 0:8f0d0ae0a077 2284 if( ValueInRange( mibSet->Param.ChannelsTxPower,
dudmuck 0:8f0d0ae0a077 2285 LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
dudmuck 0:8f0d0ae0a077 2286 {
dudmuck 0:8f0d0ae0a077 2287 LoRaMacParams.ChannelsTxPower = mibSet->Param.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 2288 }
dudmuck 0:8f0d0ae0a077 2289 else
dudmuck 0:8f0d0ae0a077 2290 {
dudmuck 0:8f0d0ae0a077 2291 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2292 }
dudmuck 0:8f0d0ae0a077 2293 break;
dudmuck 0:8f0d0ae0a077 2294 }
dudmuck 0:8f0d0ae0a077 2295 case MIB_UPLINK_COUNTER:
dudmuck 0:8f0d0ae0a077 2296 {
dudmuck 0:8f0d0ae0a077 2297 UpLinkCounter = mibSet->Param.UpLinkCounter;
dudmuck 0:8f0d0ae0a077 2298 break;
dudmuck 0:8f0d0ae0a077 2299 }
dudmuck 0:8f0d0ae0a077 2300 case MIB_DOWNLINK_COUNTER:
dudmuck 0:8f0d0ae0a077 2301 {
dudmuck 0:8f0d0ae0a077 2302 DownLinkCounter = mibSet->Param.DownLinkCounter;
dudmuck 0:8f0d0ae0a077 2303 break;
dudmuck 0:8f0d0ae0a077 2304 }
dudmuck 0:8f0d0ae0a077 2305 case MIB_SYSTEM_MAX_RX_ERROR:
dudmuck 0:8f0d0ae0a077 2306 {
Wayne Roberts 29:ad409c68c0a6 2307 LoRaMacParams.SystemMaxRxError_ms = LoRaMacParamsDefaults.SystemMaxRxError_ms = mibSet->Param.SystemMaxRxError_ms;
dudmuck 0:8f0d0ae0a077 2308 break;
dudmuck 0:8f0d0ae0a077 2309 }
dudmuck 0:8f0d0ae0a077 2310 case MIB_MIN_RX_SYMBOLS:
dudmuck 0:8f0d0ae0a077 2311 {
dudmuck 0:8f0d0ae0a077 2312 LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols = mibSet->Param.MinRxSymbols;
dudmuck 0:8f0d0ae0a077 2313 break;
dudmuck 0:8f0d0ae0a077 2314 }
dudmuck 0:8f0d0ae0a077 2315 default:
dudmuck 0:8f0d0ae0a077 2316 status = LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 2317 break;
dudmuck 0:8f0d0ae0a077 2318 }
dudmuck 0:8f0d0ae0a077 2319
dudmuck 0:8f0d0ae0a077 2320 return status;
dudmuck 0:8f0d0ae0a077 2321 }
dudmuck 0:8f0d0ae0a077 2322
dudmuck 0:8f0d0ae0a077 2323 LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam )
dudmuck 0:8f0d0ae0a077 2324 {
dudmuck 0:8f0d0ae0a077 2325 if( channelParam == NULL )
dudmuck 0:8f0d0ae0a077 2326 {
dudmuck 0:8f0d0ae0a077 2327 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2328 }
dudmuck 0:8f0d0ae0a077 2329
dudmuck 0:8f0d0ae0a077 2330 // Reset downlink counter
dudmuck 0:8f0d0ae0a077 2331 channelParam->DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 2332
dudmuck 0:8f0d0ae0a077 2333 if( MulticastChannels == NULL )
dudmuck 0:8f0d0ae0a077 2334 {
dudmuck 0:8f0d0ae0a077 2335 // New node is the fist element
dudmuck 0:8f0d0ae0a077 2336 MulticastChannels = channelParam;
dudmuck 0:8f0d0ae0a077 2337 }
dudmuck 0:8f0d0ae0a077 2338 else
dudmuck 0:8f0d0ae0a077 2339 {
dudmuck 0:8f0d0ae0a077 2340 MulticastParams_t *cur = MulticastChannels;
dudmuck 0:8f0d0ae0a077 2341
dudmuck 0:8f0d0ae0a077 2342 // Search the last node in the list
dudmuck 0:8f0d0ae0a077 2343 while( cur->Next != NULL )
dudmuck 0:8f0d0ae0a077 2344 {
dudmuck 0:8f0d0ae0a077 2345 cur = cur->Next;
dudmuck 0:8f0d0ae0a077 2346 }
dudmuck 0:8f0d0ae0a077 2347 // This function always finds the last node
dudmuck 0:8f0d0ae0a077 2348 cur->Next = channelParam;
dudmuck 0:8f0d0ae0a077 2349 }
dudmuck 0:8f0d0ae0a077 2350
dudmuck 0:8f0d0ae0a077 2351 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2352 }
dudmuck 0:8f0d0ae0a077 2353
dudmuck 0:8f0d0ae0a077 2354 LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam )
dudmuck 0:8f0d0ae0a077 2355 {
dudmuck 0:8f0d0ae0a077 2356 if( channelParam == NULL )
dudmuck 0:8f0d0ae0a077 2357 {
dudmuck 0:8f0d0ae0a077 2358 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2359 }
dudmuck 0:8f0d0ae0a077 2360
dudmuck 0:8f0d0ae0a077 2361 if( MulticastChannels != NULL )
dudmuck 0:8f0d0ae0a077 2362 {
dudmuck 0:8f0d0ae0a077 2363 if( MulticastChannels == channelParam )
dudmuck 0:8f0d0ae0a077 2364 {
dudmuck 0:8f0d0ae0a077 2365 // First element
dudmuck 0:8f0d0ae0a077 2366 MulticastChannels = channelParam->Next;
dudmuck 0:8f0d0ae0a077 2367 }
dudmuck 0:8f0d0ae0a077 2368 else
dudmuck 0:8f0d0ae0a077 2369 {
dudmuck 0:8f0d0ae0a077 2370 MulticastParams_t *cur = MulticastChannels;
dudmuck 0:8f0d0ae0a077 2371
dudmuck 0:8f0d0ae0a077 2372 // Search the node in the list
dudmuck 0:8f0d0ae0a077 2373 while( cur->Next && cur->Next != channelParam )
dudmuck 0:8f0d0ae0a077 2374 {
dudmuck 0:8f0d0ae0a077 2375 cur = cur->Next;
dudmuck 0:8f0d0ae0a077 2376 }
dudmuck 0:8f0d0ae0a077 2377 // If we found the node, remove it
dudmuck 0:8f0d0ae0a077 2378 if( cur->Next )
dudmuck 0:8f0d0ae0a077 2379 {
dudmuck 0:8f0d0ae0a077 2380 cur->Next = channelParam->Next;
dudmuck 0:8f0d0ae0a077 2381 }
dudmuck 0:8f0d0ae0a077 2382 }
dudmuck 0:8f0d0ae0a077 2383 channelParam->Next = NULL;
dudmuck 0:8f0d0ae0a077 2384 }
dudmuck 0:8f0d0ae0a077 2385
dudmuck 0:8f0d0ae0a077 2386 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2387 }
dudmuck 0:8f0d0ae0a077 2388
dudmuck 0:8f0d0ae0a077 2389 LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest )
dudmuck 0:8f0d0ae0a077 2390 {
dudmuck 0:8f0d0ae0a077 2391 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 2392 LoRaMacHeader_t macHdr;
dudmuck 0:8f0d0ae0a077 2393
dudmuck 0:8f0d0ae0a077 2394 if( mlmeRequest == NULL )
dudmuck 0:8f0d0ae0a077 2395 {
dudmuck 0:8f0d0ae0a077 2396 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2397 }
dudmuck 0:8f0d0ae0a077 2398
dudmuck 0:8f0d0ae0a077 2399 memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) );
dudmuck 0:8f0d0ae0a077 2400
dudmuck 2:f2d9aa163652 2401 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_MLMEREQ;
dudmuck 0:8f0d0ae0a077 2402
dudmuck 0:8f0d0ae0a077 2403 switch( mlmeRequest->Type )
dudmuck 0:8f0d0ae0a077 2404 {
dudmuck 0:8f0d0ae0a077 2405 case MLME_JOIN:
dudmuck 0:8f0d0ae0a077 2406 {
dudmuck 0:8f0d0ae0a077 2407 if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
dudmuck 0:8f0d0ae0a077 2408 ( mlmeRequest->Req.Join.AppEui == NULL ) ||
dudmuck 0:8f0d0ae0a077 2409 ( mlmeRequest->Req.Join.AppKey == NULL ) ||
dudmuck 0:8f0d0ae0a077 2410 ( mlmeRequest->Req.Join.NbTrials == 0 ) )
dudmuck 0:8f0d0ae0a077 2411 {
dudmuck 0:8f0d0ae0a077 2412 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2413 }
dudmuck 0:8f0d0ae0a077 2414
dudmuck 0:8f0d0ae0a077 2415 // Enables at least the usage of all datarates.
dudmuck 0:8f0d0ae0a077 2416 if( mlmeRequest->Req.Join.NbTrials < 48 )
dudmuck 0:8f0d0ae0a077 2417 {
dudmuck 0:8f0d0ae0a077 2418 mlmeRequest->Req.Join.NbTrials = 48;
dudmuck 0:8f0d0ae0a077 2419 }
dudmuck 0:8f0d0ae0a077 2420
dudmuck 0:8f0d0ae0a077 2421 LoRaMacFlags.Bits.MlmeReq = 1;
dudmuck 0:8f0d0ae0a077 2422 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
dudmuck 0:8f0d0ae0a077 2423
dudmuck 0:8f0d0ae0a077 2424 LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
dudmuck 0:8f0d0ae0a077 2425 LoRaMacAppEui = mlmeRequest->Req.Join.AppEui;
dudmuck 0:8f0d0ae0a077 2426 LoRaMacAppKey = mlmeRequest->Req.Join.AppKey;
dudmuck 0:8f0d0ae0a077 2427 MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials;
dudmuck 0:8f0d0ae0a077 2428
dudmuck 0:8f0d0ae0a077 2429 // Reset variable JoinRequestTrials
dudmuck 0:8f0d0ae0a077 2430 JoinRequestTrials = 0;
dudmuck 0:8f0d0ae0a077 2431
dudmuck 0:8f0d0ae0a077 2432 // Setup header information
dudmuck 0:8f0d0ae0a077 2433 macHdr.Value = 0;
dudmuck 0:8f0d0ae0a077 2434 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
dudmuck 0:8f0d0ae0a077 2435
dudmuck 0:8f0d0ae0a077 2436 ResetMacParameters( );
Wayne Roberts 29:ad409c68c0a6 2437 LoRaMacFlags.Bits.expecting_beacon = false;
dudmuck 16:915815632c1f 2438 BeaconCtx.state = BEACON_STATE_NONE;
dudmuck 0:8f0d0ae0a077 2439
dudmuck 0:8f0d0ae0a077 2440 Channel = 0; // start with first channel
Wayne Roberts 29:ad409c68c0a6 2441 mac_printf("<ch0>");
Wayne Roberts 29:ad409c68c0a6 2442 mac_printf("mlme-join-send ch%u\r\n", Channel);
dudmuck 0:8f0d0ae0a077 2443 status = Send( &macHdr, 0, NULL, 0 );
dudmuck 0:8f0d0ae0a077 2444 break;
dudmuck 0:8f0d0ae0a077 2445 }
dudmuck 0:8f0d0ae0a077 2446 case MLME_LINK_CHECK:
dudmuck 0:8f0d0ae0a077 2447 {
dudmuck 0:8f0d0ae0a077 2448 LoRaMacFlags.Bits.MlmeReq = 1;
dudmuck 0:8f0d0ae0a077 2449 // LoRaMac will send this command piggy-pack
dudmuck 0:8f0d0ae0a077 2450 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
dudmuck 0:8f0d0ae0a077 2451
dudmuck 0:8f0d0ae0a077 2452 status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
dudmuck 0:8f0d0ae0a077 2453 break;
dudmuck 0:8f0d0ae0a077 2454 }
dudmuck 0:8f0d0ae0a077 2455 case MLME_TXCW:
dudmuck 0:8f0d0ae0a077 2456 {
dudmuck 0:8f0d0ae0a077 2457 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
dudmuck 0:8f0d0ae0a077 2458 LoRaMacFlags.Bits.MlmeReq = 1;
dudmuck 0:8f0d0ae0a077 2459 status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout );
dudmuck 0:8f0d0ae0a077 2460 break;
dudmuck 0:8f0d0ae0a077 2461 }
dudmuck 0:8f0d0ae0a077 2462 case MLME_TXCW_1:
dudmuck 0:8f0d0ae0a077 2463 {
dudmuck 0:8f0d0ae0a077 2464 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
dudmuck 0:8f0d0ae0a077 2465 LoRaMacFlags.Bits.MlmeReq = 1;
dudmuck 0:8f0d0ae0a077 2466 status = SetTxContinuousWave1( mlmeRequest->Req.TxCw.Timeout, mlmeRequest->Req.TxCw.Frequency, mlmeRequest->Req.TxCw.Power );
dudmuck 0:8f0d0ae0a077 2467 break;
dudmuck 0:8f0d0ae0a077 2468 }
dudmuck 0:8f0d0ae0a077 2469 default:
dudmuck 0:8f0d0ae0a077 2470 break;
dudmuck 0:8f0d0ae0a077 2471 }
dudmuck 0:8f0d0ae0a077 2472
dudmuck 0:8f0d0ae0a077 2473 if( status != LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 2474 {
Wayne Roberts 29:ad409c68c0a6 2475 LoRaMacFlags.Bits.NodeAckRequested = false;
dudmuck 0:8f0d0ae0a077 2476 LoRaMacFlags.Bits.MlmeReq = 0;
dudmuck 0:8f0d0ae0a077 2477 }
dudmuck 0:8f0d0ae0a077 2478
dudmuck 0:8f0d0ae0a077 2479 return status;
dudmuck 0:8f0d0ae0a077 2480 }
dudmuck 0:8f0d0ae0a077 2481
dudmuck 0:8f0d0ae0a077 2482 LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest )
dudmuck 0:8f0d0ae0a077 2483 {
dudmuck 0:8f0d0ae0a077 2484 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 2485 LoRaMacHeader_t macHdr;
dudmuck 0:8f0d0ae0a077 2486 uint8_t fPort = 0;
dudmuck 0:8f0d0ae0a077 2487 void *fBuffer;
dudmuck 0:8f0d0ae0a077 2488 uint16_t fBufferSize;
dudmuck 0:8f0d0ae0a077 2489 bool readyToSend = false;
dudmuck 0:8f0d0ae0a077 2490
dudmuck 0:8f0d0ae0a077 2491 if( mcpsRequest == NULL )
dudmuck 0:8f0d0ae0a077 2492 {
dudmuck 0:8f0d0ae0a077 2493 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2494 }
dudmuck 0:8f0d0ae0a077 2495
dudmuck 0:8f0d0ae0a077 2496 macHdr.Value = 0;
dudmuck 0:8f0d0ae0a077 2497 memset1 ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) );
dudmuck 2:f2d9aa163652 2498 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_MCPSREQ;
dudmuck 0:8f0d0ae0a077 2499
dudmuck 0:8f0d0ae0a077 2500 switch( mcpsRequest->Type )
dudmuck 0:8f0d0ae0a077 2501 {
dudmuck 0:8f0d0ae0a077 2502 case MCPS_UNCONFIRMED:
dudmuck 0:8f0d0ae0a077 2503 {
dudmuck 0:8f0d0ae0a077 2504 readyToSend = true;
dudmuck 0:8f0d0ae0a077 2505
dudmuck 0:8f0d0ae0a077 2506 macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
dudmuck 0:8f0d0ae0a077 2507 fPort = mcpsRequest->Req.Unconfirmed.fPort;
dudmuck 0:8f0d0ae0a077 2508 fBuffer = mcpsRequest->Req.Unconfirmed.fBuffer;
dudmuck 0:8f0d0ae0a077 2509 fBufferSize = mcpsRequest->Req.Unconfirmed.fBufferSize;
dudmuck 0:8f0d0ae0a077 2510 break;
dudmuck 0:8f0d0ae0a077 2511 }
dudmuck 0:8f0d0ae0a077 2512 case MCPS_CONFIRMED:
dudmuck 0:8f0d0ae0a077 2513 {
dudmuck 0:8f0d0ae0a077 2514 readyToSend = true;
dudmuck 0:8f0d0ae0a077 2515
dudmuck 0:8f0d0ae0a077 2516 macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
dudmuck 0:8f0d0ae0a077 2517 fPort = mcpsRequest->Req.Confirmed.fPort;
dudmuck 0:8f0d0ae0a077 2518 fBuffer = mcpsRequest->Req.Confirmed.fBuffer;
dudmuck 0:8f0d0ae0a077 2519 fBufferSize = mcpsRequest->Req.Confirmed.fBufferSize;
dudmuck 0:8f0d0ae0a077 2520 break;
dudmuck 0:8f0d0ae0a077 2521 }
dudmuck 0:8f0d0ae0a077 2522 case MCPS_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 2523 {
dudmuck 0:8f0d0ae0a077 2524 readyToSend = true;
dudmuck 0:8f0d0ae0a077 2525
dudmuck 0:8f0d0ae0a077 2526 macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
dudmuck 0:8f0d0ae0a077 2527 fBuffer = mcpsRequest->Req.Proprietary.fBuffer;
dudmuck 0:8f0d0ae0a077 2528 fBufferSize = mcpsRequest->Req.Proprietary.fBufferSize;
dudmuck 0:8f0d0ae0a077 2529 break;
dudmuck 0:8f0d0ae0a077 2530 }
dudmuck 0:8f0d0ae0a077 2531 default:
dudmuck 0:8f0d0ae0a077 2532 break;
dudmuck 0:8f0d0ae0a077 2533 }
dudmuck 0:8f0d0ae0a077 2534
Wayne Roberts 29:ad409c68c0a6 2535 if (readyToSend)
dudmuck 0:8f0d0ae0a077 2536 {
dudmuck 0:8f0d0ae0a077 2537 status = Send( &macHdr, fPort, fBuffer, fBufferSize );
Wayne Roberts 29:ad409c68c0a6 2538 if (status == LORAMAC_STATUS_OK)
dudmuck 0:8f0d0ae0a077 2539 {
dudmuck 0:8f0d0ae0a077 2540 McpsConfirm.McpsRequest = mcpsRequest->Type;
dudmuck 0:8f0d0ae0a077 2541 LoRaMacFlags.Bits.McpsReq = 1;
dudmuck 0:8f0d0ae0a077 2542 }
dudmuck 0:8f0d0ae0a077 2543 else
dudmuck 0:8f0d0ae0a077 2544 {
Wayne Roberts 29:ad409c68c0a6 2545 LoRaMacFlags.Bits.NodeAckRequested = false;
dudmuck 0:8f0d0ae0a077 2546 }
dudmuck 0:8f0d0ae0a077 2547 }
dudmuck 0:8f0d0ae0a077 2548
dudmuck 0:8f0d0ae0a077 2549 return status;
dudmuck 0:8f0d0ae0a077 2550 }
dudmuck 0:8f0d0ae0a077 2551
dudmuck 0:8f0d0ae0a077 2552 void LoRaMacTestRxWindowsOn( bool enable )
dudmuck 0:8f0d0ae0a077 2553 {
dudmuck 0:8f0d0ae0a077 2554 IsRxWindowsEnabled = enable;
dudmuck 0:8f0d0ae0a077 2555 }
dudmuck 0:8f0d0ae0a077 2556
dudmuck 0:8f0d0ae0a077 2557 void LoRaMacTestSetMic( uint16_t txPacketCounter )
dudmuck 0:8f0d0ae0a077 2558 {
dudmuck 0:8f0d0ae0a077 2559 UpLinkCounter = txPacketCounter;
dudmuck 16:915815632c1f 2560 //IsUpLinkCounterFixed = true;
dudmuck 0:8f0d0ae0a077 2561 }
dudmuck 0:8f0d0ae0a077 2562
dudmuck 0:8f0d0ae0a077 2563 void LoRaMacTestSetChannel( uint8_t channel )
dudmuck 0:8f0d0ae0a077 2564 {
Wayne Roberts 29:ad409c68c0a6 2565 mac_printf("set-testch%u\r\n", channel);
dudmuck 0:8f0d0ae0a077 2566 Channel = channel;
dudmuck 0:8f0d0ae0a077 2567 }
dudmuck 0:8f0d0ae0a077 2568
dudmuck 0:8f0d0ae0a077 2569
dudmuck 0:8f0d0ae0a077 2570 static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError )
dudmuck 0:8f0d0ae0a077 2571 {
Wayne Roberts 29:ad409c68c0a6 2572 RxConfigParams_t rxConfigParams = { 0, 0 };
dudmuck 0:8f0d0ae0a077 2573 double tSymbol = 0.0;
dudmuck 0:8f0d0ae0a077 2574
dudmuck 0:8f0d0ae0a077 2575 rxConfigParams.Datarate = datarate;
dudmuck 0:8f0d0ae0a077 2576
dudmuck 0:8f0d0ae0a077 2577 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
dudmuck 0:8f0d0ae0a077 2578 if( datarate == DR_7 )
dudmuck 0:8f0d0ae0a077 2579 { // FSK
dudmuck 0:8f0d0ae0a077 2580 tSymbol = ( 1.0 / ( double )Datarates[datarate] ) * 8.0; // 1 symbol equals 1 byte
dudmuck 0:8f0d0ae0a077 2581 }
dudmuck 0:8f0d0ae0a077 2582 else
dudmuck 0:8f0d0ae0a077 2583 #endif
dudmuck 0:8f0d0ae0a077 2584 { // LoRa
Wayne Roberts 29:ad409c68c0a6 2585 tSymbol = ( ( double )( 1 << Datarates[datarate] ) / LORA_BANDWIDTH_KHZ ) * 1e3;
dudmuck 0:8f0d0ae0a077 2586 }
dudmuck 0:8f0d0ae0a077 2587
dudmuck 0:8f0d0ae0a077 2588 rxConfigParams.RxWindowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * LoRaMacParams.MinRxSymbols - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), LoRaMacParams.MinRxSymbols ); // Computed number of symbols
Wayne Roberts 34:9c8966cd66a2 2589 mac_printf("RxWindowTimeout:%lu\r\n", rxConfigParams.RxWindowTimeout);
dudmuck 0:8f0d0ae0a077 2590
dudmuck 0:8f0d0ae0a077 2591 return rxConfigParams;
dudmuck 0:8f0d0ae0a077 2592 }
dudmuck 0:8f0d0ae0a077 2593
dudmuck 20:42839629a5dc 2594 void LoRaMacBottomHalf()
dudmuck 20:42839629a5dc 2595 {
Wayne Roberts 29:ad409c68c0a6 2596 if (LoRaMacFlags.Bits.join_send) {
Wayne Roberts 29:ad409c68c0a6 2597 join_send_bh();
Wayne Roberts 29:ad409c68c0a6 2598 LoRaMacFlags.Bits.join_send = 0;
dudmuck 20:42839629a5dc 2599 }
Wayne Roberts 29:ad409c68c0a6 2600 if (LoRaMacFlags.Bits.send) {
Wayne Roberts 29:ad409c68c0a6 2601 send_bh();
Wayne Roberts 29:ad409c68c0a6 2602 LoRaMacFlags.Bits.send = 0;
dudmuck 20:42839629a5dc 2603 }
Wayne Roberts 29:ad409c68c0a6 2604
Wayne Roberts 29:ad409c68c0a6 2605 if (LoRaMacFlags.Bits.reJoin) {
Wayne Roberts 29:ad409c68c0a6 2606 MlmeReq_t mlmeReq;
Wayne Roberts 29:ad409c68c0a6 2607 mlmeReq.Type = MLME_JOIN;
Wayne Roberts 29:ad409c68c0a6 2608
Wayne Roberts 29:ad409c68c0a6 2609 mlmeReq.Req.Join.DevEui = LoRaMacDevEui;
Wayne Roberts 29:ad409c68c0a6 2610 mlmeReq.Req.Join.AppEui = LoRaMacAppEui;
Wayne Roberts 29:ad409c68c0a6 2611 mlmeReq.Req.Join.AppKey = LoRaMacAppKey;
Wayne Roberts 29:ad409c68c0a6 2612 mlmeReq.Req.Join.NbTrials = 255;
Wayne Roberts 29:ad409c68c0a6 2613
Wayne Roberts 29:ad409c68c0a6 2614 if (LoRaMacMlmeRequest(&mlmeReq) == LORAMAC_STATUS_OK)
Wayne Roberts 29:ad409c68c0a6 2615 LoRaMacFlags.Bits.reJoin = 0;
dudmuck 20:42839629a5dc 2616 }
Wayne Roberts 29:ad409c68c0a6 2617
Wayne Roberts 29:ad409c68c0a6 2618 Radio::service();
dudmuck 20:42839629a5dc 2619 }