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:
Fri Dec 07 17:57:41 2018 -0800
Revision:
29:ad409c68c0a6
Parent:
25:fed9d5b77183
Child:
30:1c35c4f56e50
update to latest radio HAL

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