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:
Thu Dec 13 16:53:02 2018 -0800
Revision:
30:1c35c4f56e50
Parent:
29:ad409c68c0a6
add sx1280, add beacon duration to join accept

Who changed what in which revision?

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