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:
Sun Dec 16 10:22:21 2018 -0800
Revision:
31:6ed03f61af64
Parent:
mac/LoRaMac.cpp@30:1c35c4f56e50
Child:
32:ac904adfc842
rename header file due to header with same name in mbed-os

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