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:
Wed Dec 19 13:56:04 2018 -0800
Revision:
33:bc0b6be19e07
Parent:
32:ac904adfc842
Child:
34:9c8966cd66a2
for rx window timer, capture txDone using rx window timer

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 33:bc0b6be19e07 706 int diff = _rx_timeout_setAt - _rx_timeout.read_us();
Wayne Roberts 29:ad409c68c0a6 707 RxWindowSetup(Channels[Channel].Frequency, RxWindowsParam.Datarate, RxWindowsParam.RxWindowTimeout, false);
Wayne Roberts 29:ad409c68c0a6 708 Radio::Rx( LoRaMacParams.MaxRxWindow );
Wayne Roberts 29:ad409c68c0a6 709 //mac_printf("rxwinTo:%u\r\n", RxWindowsParam.RxWindowTimeout);
Wayne Roberts 29:ad409c68c0a6 710 }
Wayne Roberts 29:ad409c68c0a6 711
dudmuck 0:8f0d0ae0a077 712 static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError );
dudmuck 0:8f0d0ae0a077 713
Wayne Roberts 33:bc0b6be19e07 714 volatile us_timestamp_t rxto_irqAt;
Wayne Roberts 33:bc0b6be19e07 715
Wayne Roberts 33:bc0b6be19e07 716 static void OnRadioTxDone_topHalf()
Wayne Roberts 33:bc0b6be19e07 717 {
Wayne Roberts 33:bc0b6be19e07 718 rxto_irqAt = _rx_timeout.read_us();
Wayne Roberts 33:bc0b6be19e07 719 }
Wayne Roberts 33:bc0b6be19e07 720
Wayne Roberts 29:ad409c68c0a6 721 static void OnRadioTxDone_bh()
dudmuck 0:8f0d0ae0a077 722 {
dudmuck 0:8f0d0ae0a077 723 // Setup timers
dudmuck 16:915815632c1f 724 if (IsRxWindowsEnabled)
dudmuck 0:8f0d0ae0a077 725 {
Wayne Roberts 33:bc0b6be19e07 726 _rx_timeout_setAt = rxto_irqAt + RxWindowDelay_us;
Wayne Roberts 29:ad409c68c0a6 727 _rx_timeout.attach_us(&OnRxWindowTimerEvent, _rx_timeout_setAt);
Wayne Roberts 29:ad409c68c0a6 728 if (LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 729 {
dudmuck 0:8f0d0ae0a077 730 AckTimeoutTimer.attach_us(&OnAckTimeoutTimerEvent, (RxWindowDelay_us/1000) + ACK_TIMEOUT_us + randr(-ACK_TIMEOUT_RND_us, ACK_TIMEOUT_RND_us));
dudmuck 0:8f0d0ae0a077 731 }
dudmuck 0:8f0d0ae0a077 732 }
dudmuck 0:8f0d0ae0a077 733 else
dudmuck 0:8f0d0ae0a077 734 {
dudmuck 0:8f0d0ae0a077 735 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 736 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 737
dudmuck 0:8f0d0ae0a077 738 if( LoRaMacFlags.Value == 0 )
dudmuck 0:8f0d0ae0a077 739 {
dudmuck 0:8f0d0ae0a077 740 LoRaMacFlags.Bits.McpsReq = 1;
dudmuck 0:8f0d0ae0a077 741 }
dudmuck 0:8f0d0ae0a077 742 LoRaMacFlags.Bits.MacDone = 1;
dudmuck 0:8f0d0ae0a077 743 }
Wayne Roberts 29:ad409c68c0a6 744
Wayne Roberts 29:ad409c68c0a6 745 if (!LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 746 {
dudmuck 0:8f0d0ae0a077 747 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 748 ChannelsNbRepCounter++;
dudmuck 0:8f0d0ae0a077 749 }
Wayne Roberts 29:ad409c68c0a6 750
dudmuck 10:00997daeb0c0 751 MlmeIndication.MlmeIndication = MLME_TXDONE;
dudmuck 10:00997daeb0c0 752 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 753 LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
Wayne Roberts 29:ad409c68c0a6 754
Wayne Roberts 29:ad409c68c0a6 755 Radio::Standby( );
Wayne Roberts 29:ad409c68c0a6 756
Wayne Roberts 29:ad409c68c0a6 757 txDoneAt = Radio::irqAt + lpt_offset;
dudmuck 16:915815632c1f 758 }
dudmuck 16:915815632c1f 759
dudmuck 16:915815632c1f 760
dudmuck 16:915815632c1f 761 static void application_callbacks()
dudmuck 16:915815632c1f 762 {
dudmuck 16:915815632c1f 763 if (LoRaMacFlags.Bits.McpsInd) {
dudmuck 16:915815632c1f 764 LoRaMacFlags.Bits.McpsInd = 0;
dudmuck 16:915815632c1f 765 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
dudmuck 16:915815632c1f 766 }
Wayne Roberts 29:ad409c68c0a6 767
dudmuck 16:915815632c1f 768 if (LoRaMacFlags.Bits.McpsReq) {
dudmuck 16:915815632c1f 769 LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm );
dudmuck 16:915815632c1f 770 LoRaMacFlags.Bits.McpsReq = 0;
Wayne Roberts 29:ad409c68c0a6 771 }
dudmuck 0:8f0d0ae0a077 772 }
dudmuck 0:8f0d0ae0a077 773
dudmuck 0:8f0d0ae0a077 774 static void PrepareRxDoneAbort( void )
dudmuck 0:8f0d0ae0a077 775 {
Wayne Roberts 29:ad409c68c0a6 776 if (LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 777 {
dudmuck 0:8f0d0ae0a077 778 OnAckTimeoutTimerEvent( );
dudmuck 0:8f0d0ae0a077 779 }
dudmuck 0:8f0d0ae0a077 780
dudmuck 0:8f0d0ae0a077 781 LoRaMacFlags.Bits.McpsInd = 1;
dudmuck 0:8f0d0ae0a077 782 LoRaMacFlags.Bits.MacDone = 1;
Wayne Roberts 29:ad409c68c0a6 783
dudmuck 16:915815632c1f 784 application_callbacks();
dudmuck 0:8f0d0ae0a077 785 }
dudmuck 0:8f0d0ae0a077 786
dudmuck 20:42839629a5dc 787 void send_bh()
Wayne Roberts 29:ad409c68c0a6 788 {
dudmuck 25:fed9d5b77183 789 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_SEND;
dudmuck 25:fed9d5b77183 790 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_SEND;
Wayne Roberts 29:ad409c68c0a6 791 McpsConfirm.TxPower = LoRaMacParams.ChannelsTxPower;
dudmuck 25:fed9d5b77183 792 McpsConfirm.UpLinkFrequency = Channels[Channel].Frequency;
dudmuck 25:fed9d5b77183 793
Wayne Roberts 29:ad409c68c0a6 794 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) // joining is channel hunting
Wayne Roberts 29:ad409c68c0a6 795 Radio::SetChannel( Channels[Channel].Frequency );
Wayne Roberts 29:ad409c68c0a6 796
Wayne Roberts 29:ad409c68c0a6 797 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
dudmuck 25:fed9d5b77183 798 {
dudmuck 25:fed9d5b77183 799 JoinRequestTrials++;
Wayne Roberts 29:ad409c68c0a6 800 mac_printf("join %luhz try%u DR%u\r\n", Channels[Channel].Frequency, JoinRequestTrials, LoRaMacParams.ChannelsDatarate_fixed);
dudmuck 25:fed9d5b77183 801 }
dudmuck 25:fed9d5b77183 802
Wayne Roberts 29:ad409c68c0a6 803 Radio::set_tx_dbm(TxPowers[LoRaMacParams.ChannelsTxPower]);
Wayne Roberts 29:ad409c68c0a6 804 Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, Datarates[LoRaMacParams.ChannelsDatarate_fixed], 1);
Wayne Roberts 29:ad409c68c0a6 805
Wayne Roberts 29:ad409c68c0a6 806 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 29:ad409c68c0a6 807 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false);
Wayne Roberts 29:ad409c68c0a6 808 Radio::Send(tx_buf_len, 0, 0, 0);
Wayne Roberts 29:ad409c68c0a6 809
dudmuck 25:fed9d5b77183 810 LoRaMacFlags.Bits.uplink_pending = 0; // sent
dudmuck 25:fed9d5b77183 811
dudmuck 25:fed9d5b77183 812 // Compute Rx1 windows parameters, taken at TxDone
Wayne Roberts 29:ad409c68c0a6 813 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
Wayne Roberts 29:ad409c68c0a6 814 RxWindowDelay_us = LoRaMacParams.JoinAcceptDelay_us - TARGET_PRECESSION_us;
dudmuck 25:fed9d5b77183 815 else
Wayne Roberts 29:ad409c68c0a6 816 RxWindowDelay_us = LoRaMacParams.ReceiveDelay_us - TARGET_PRECESSION_us;
Wayne Roberts 29:ad409c68c0a6 817
Wayne Roberts 29:ad409c68c0a6 818 } // ..send_bh()
dudmuck 20:42839629a5dc 819
dudmuck 20:42839629a5dc 820 void send_callback()
Wayne Roberts 29:ad409c68c0a6 821 {
Wayne Roberts 29:ad409c68c0a6 822 int err = 0;
Wayne Roberts 29:ad409c68c0a6 823 us_timestamp_t now = BeaconCtx.sendAt + BeaconCtx.lastSendAtErr;
Wayne Roberts 29:ad409c68c0a6 824
dudmuck 20:42839629a5dc 825 if (BeaconCtx.guard) {
dudmuck 25:fed9d5b77183 826 /* last send, this will be restarted after beacon sent */
dudmuck 20:42839629a5dc 827 return;
dudmuck 20:42839629a5dc 828 }
Wayne Roberts 29:ad409c68c0a6 829 BeaconCtx.sendOpportunities++;
Wayne Roberts 29:ad409c68c0a6 830
Wayne Roberts 29:ad409c68c0a6 831 BeaconCtx.sendAt += BeaconCtx.periodicity_slots * PING_SLOT_RESOLUTION_us;
Wayne Roberts 29:ad409c68c0a6 832 if (BeaconCtx.state == BEACON_STATE_LOCKED) {
Wayne Roberts 29:ad409c68c0a6 833 float sinceBeacon = now - BeaconCtx.LastBeaconRx_us;
Wayne Roberts 29:ad409c68c0a6 834 float ratio = sinceBeacon / BEACON_INTERVAL_us;
Wayne Roberts 29:ad409c68c0a6 835 err = BeaconCtx.last_BeaconRxTimerError_us * ratio;
Wayne Roberts 29:ad409c68c0a6 836 }
Wayne Roberts 29:ad409c68c0a6 837 _tx_timeout.attach_us(&send_callback, BeaconCtx.sendAt + err);
Wayne Roberts 29:ad409c68c0a6 838 BeaconCtx.lastSendAtErr = err;
Wayne Roberts 29:ad409c68c0a6 839
Wayne Roberts 30:1c35c4f56e50 840 if (LoRaMacFlags.Bits.uplink_pending) {
Wayne Roberts 30:1c35c4f56e50 841 us_timestamp_t untilGuard = (BeaconCtx.rx_setup_at - BEACON_GUARD_us) - BeaconCtx._timeout_guard.read_us();
Wayne Roberts 30:1c35c4f56e50 842 if (untilGuard > (RECEIVE_DELAY_us + TARGET_PRECESSION_us))
Wayne Roberts 30:1c35c4f56e50 843 LoRaMacFlags.Bits.send = 1;
Wayne Roberts 30:1c35c4f56e50 844 }
dudmuck 0:8f0d0ae0a077 845 }
dudmuck 0:8f0d0ae0a077 846
dudmuck 0:8f0d0ae0a077 847 void OnRxBeaconSetup()
dudmuck 0:8f0d0ae0a077 848 {
Wayne Roberts 30:1c35c4f56e50 849 BeaconCtx.guard = false;
Wayne Roberts 29:ad409c68c0a6 850 LoRaMacFlags.Bits.expecting_beacon = true;
Wayne Roberts 29:ad409c68c0a6 851
Wayne Roberts 29:ad409c68c0a6 852 Radio::Rx(2000);
Wayne Roberts 29:ad409c68c0a6 853
Wayne Roberts 29:ad409c68c0a6 854 BeaconCtx.lastSendAtErr = 0;
dudmuck 16:915815632c1f 855 }
dudmuck 16:915815632c1f 856
dudmuck 16:915815632c1f 857 void guard_callback()
dudmuck 16:915815632c1f 858 {
dudmuck 16:915815632c1f 859 BeaconCtx.guard = true;
Wayne Roberts 30:1c35c4f56e50 860 Radio::Standby( );
Wayne Roberts 30:1c35c4f56e50 861 Radio::SetChannel( Channels[Channel].Frequency );
dudmuck 21:500ff43d8424 862
Wayne Roberts 29:ad409c68c0a6 863 _tx_timeout.detach();
Wayne Roberts 29:ad409c68c0a6 864 mac_printf("sendOpportunities:%u\r\n", BeaconCtx.sendOpportunities);
Wayne Roberts 29:ad409c68c0a6 865 BeaconCtx.sendOpportunities = 0;
Wayne Roberts 30:1c35c4f56e50 866
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 Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, Datarates[BEACON_CHANNEL_DR], 1);
Wayne Roberts 30:1c35c4f56e50 870 Radio::SetFixedPayloadLength(BEACON_SIZE);
Wayne Roberts 30:1c35c4f56e50 871
Wayne Roberts 30:1c35c4f56e50 872 #ifdef SX128x_H
Wayne Roberts 30:1c35c4f56e50 873 /* explicit to implicit header: does sx1280 really need this a 2nd time? */
Wayne Roberts 30:1c35c4f56e50 874 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 30:1c35c4f56e50 875 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, true, false, false);
Wayne Roberts 30:1c35c4f56e50 876 #endif /* SX128x_H */
Wayne Roberts 30:1c35c4f56e50 877 Radio::SetLoRaSymbolTimeout(BeaconCtx.nSymbsTimeout);
dudmuck 0:8f0d0ae0a077 878 }
dudmuck 0:8f0d0ae0a077 879
Wayne Roberts 29:ad409c68c0a6 880 static void us_to_nSymbTimeout(unsigned us)
dudmuck 0:8f0d0ae0a077 881 {
Wayne Roberts 29:ad409c68c0a6 882 mac_printf("symTo:%u ", us);
Wayne Roberts 29:ad409c68c0a6 883 BeaconCtx.nSymbsTimeout = us / BeaconCtx.symbol_period_us;
Wayne Roberts 29:ad409c68c0a6 884 if (BeaconCtx.nSymbsTimeout < (MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols)) {
Wayne Roberts 29:ad409c68c0a6 885 BeaconCtx.nSymbsTimeout = MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols;
Wayne Roberts 29:ad409c68c0a6 886 } else if (BeaconCtx.nSymbsTimeout > 255)
Wayne Roberts 29:ad409c68c0a6 887 BeaconCtx.nSymbsTimeout = 255;
Wayne Roberts 29:ad409c68c0a6 888
Wayne Roberts 29:ad409c68c0a6 889 BeaconCtx.SymbolTimeout_us = BeaconCtx.nSymbsTimeout * BeaconCtx.symbol_period_us;
Wayne Roberts 29:ad409c68c0a6 890 mac_printf("%u\r\n", BeaconCtx.nSymbsTimeout);
dudmuck 0:8f0d0ae0a077 891 }
dudmuck 0:8f0d0ae0a077 892
dudmuck 0:8f0d0ae0a077 893 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
dudmuck 0:8f0d0ae0a077 894 {
dudmuck 0:8f0d0ae0a077 895 // The CRC calculation follows CCITT
dudmuck 0:8f0d0ae0a077 896 const uint16_t polynom = 0x1021;
dudmuck 0:8f0d0ae0a077 897 // CRC initial value
dudmuck 0:8f0d0ae0a077 898 uint16_t crc = 0x0000;
dudmuck 0:8f0d0ae0a077 899
dudmuck 0:8f0d0ae0a077 900 if( buffer == NULL )
dudmuck 0:8f0d0ae0a077 901 {
dudmuck 0:8f0d0ae0a077 902 return 0;
dudmuck 0:8f0d0ae0a077 903 }
dudmuck 0:8f0d0ae0a077 904
dudmuck 0:8f0d0ae0a077 905 for( uint16_t i = 0; i < length; ++i )
dudmuck 0:8f0d0ae0a077 906 {
dudmuck 0:8f0d0ae0a077 907 crc ^= ( uint16_t ) buffer[i] << 8;
dudmuck 0:8f0d0ae0a077 908 for( uint16_t j = 0; j < 8; ++j )
dudmuck 0:8f0d0ae0a077 909 {
dudmuck 0:8f0d0ae0a077 910 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
dudmuck 0:8f0d0ae0a077 911 }
dudmuck 0:8f0d0ae0a077 912 }
dudmuck 0:8f0d0ae0a077 913
dudmuck 0:8f0d0ae0a077 914 return crc;
dudmuck 0:8f0d0ae0a077 915 }
dudmuck 0:8f0d0ae0a077 916
Wayne Roberts 29:ad409c68c0a6 917 void rx_beacon(uint16_t size)
dudmuck 0:8f0d0ae0a077 918 {
dudmuck 0:8f0d0ae0a077 919 static bool compensate_precession = false;
dudmuck 0:8f0d0ae0a077 920 int32_t compensation = 0;
Wayne Roberts 30:1c35c4f56e50 921 us_timestamp_t ThisBeaconRx_us = Radio::irqAt + lpt_offset - BeaconCtx.beaconStartToRxDone;
Wayne Roberts 29:ad409c68c0a6 922
Wayne Roberts 30:1c35c4f56e50 923 BeaconCtx.num_consecutive_ok++;
Wayne Roberts 29:ad409c68c0a6 924 mac_printf("rx_beacon %llu ", Radio::irqAt);
Wayne Roberts 29:ad409c68c0a6 925 BeaconCtx.rx_precession_us = ThisBeaconRx_us - BeaconCtx.rx_setup_at;
dudmuck 0:8f0d0ae0a077 926 if (BeaconCtx.state != BEACON_STATE_FIRST_ACQ) {
dudmuck 13:18de9ee3a461 927 BeaconCtx.known_working_BeaconRxTimerError_us = BeaconCtx.last_BeaconRxTimerError_us;
Wayne Roberts 29:ad409c68c0a6 928 BeaconCtx.last_BeaconRxTimerError_us = (ThisBeaconRx_us - BeaconCtx.LastBeaconRx_us) - (BEACON_INTERVAL_us * (BeaconCtx.num_missed+1));
Wayne Roberts 29:ad409c68c0a6 929
Wayne Roberts 29:ad409c68c0a6 930 if (BeaconCtx.num_missed > 0) {
Wayne Roberts 29:ad409c68c0a6 931 /* Timer error is measured over more than one beacon period.
Wayne Roberts 29:ad409c68c0a6 932 * Scale to error seen over single beacon period */
Wayne Roberts 29:ad409c68c0a6 933 BeaconCtx.last_BeaconRxTimerError_us /= BeaconCtx.num_missed + 1;
dudmuck 0:8f0d0ae0a077 934 }
dudmuck 0:8f0d0ae0a077 935
dudmuck 0:8f0d0ae0a077 936 if (BeaconCtx.state == BEACON_STATE_ACQ_ERROR) {
Wayne Roberts 29:ad409c68c0a6 937 mac_printf("-->LOCKED ");
dudmuck 21:500ff43d8424 938 BeaconCtx.state = BEACON_STATE_LOCKED;
dudmuck 0:8f0d0ae0a077 939 compensate_precession = true;
dudmuck 0:8f0d0ae0a077 940 }
dudmuck 0:8f0d0ae0a077 941 } else {
dudmuck 0:8f0d0ae0a077 942 /* ignore precession at first acquisition because it has slot resolution added */
Wayne Roberts 29:ad409c68c0a6 943 mac_printf("-->ACQ_ERROR ");
dudmuck 0:8f0d0ae0a077 944 // next beacon will give us our crystal error
dudmuck 0:8f0d0ae0a077 945 BeaconCtx.state = BEACON_STATE_ACQ_ERROR;
dudmuck 0:8f0d0ae0a077 946 }
dudmuck 0:8f0d0ae0a077 947
Wayne Roberts 29:ad409c68c0a6 948 mac_printf("err%d=%llu-%llu ", BeaconCtx.last_BeaconRxTimerError_us, ThisBeaconRx_us, BeaconCtx.LastBeaconRx_us);
Wayne Roberts 29:ad409c68c0a6 949 if (BeaconCtx.num_missed > 0)
Wayne Roberts 29:ad409c68c0a6 950 mac_printf("missed%u ", BeaconCtx.num_missed);
Wayne Roberts 29:ad409c68c0a6 951
Wayne Roberts 29:ad409c68c0a6 952 mac_printf(" rx-before-tx:%d ", BeaconCtx.rx_precession_us);
Wayne Roberts 29:ad409c68c0a6 953 if (BeaconCtx.last_BeaconRxTimerError_us > 40000 || BeaconCtx.last_BeaconRxTimerError_us < -40000) {
Wayne Roberts 29:ad409c68c0a6 954 BeaconCtx._timeout_rx.detach();
Wayne Roberts 29:ad409c68c0a6 955 BeaconCtx._timeout_guard.detach();
Wayne Roberts 29:ad409c68c0a6 956 mac_printf("halt\r\n");
Wayne Roberts 29:ad409c68c0a6 957 for (;;) asm("nop");
Wayne Roberts 29:ad409c68c0a6 958 }
dudmuck 0:8f0d0ae0a077 959 BeaconCtx.LastBeaconRx_us = ThisBeaconRx_us;
dudmuck 0:8f0d0ae0a077 960
dudmuck 21:500ff43d8424 961 if (BeaconCtx.state == BEACON_STATE_LOCKED) {
dudmuck 0:8f0d0ae0a077 962 if (compensate_precession) {
Wayne Roberts 29:ad409c68c0a6 963 compensation = BeaconCtx.rx_precession_us - TARGET_PRECESSION_us + BeaconCtx.last_BeaconRxTimerError_us;
Wayne Roberts 29:ad409c68c0a6 964 mac_printf(" comp%ld", compensation);
dudmuck 0:8f0d0ae0a077 965 }
dudmuck 0:8f0d0ae0a077 966 }
dudmuck 0:8f0d0ae0a077 967
Wayne Roberts 29:ad409c68c0a6 968 // reference tick for uplink schedule: when gateway started beacon
Wayne Roberts 29:ad409c68c0a6 969 BeaconCtx.sendAt = BeaconCtx.rx_setup_at + BeaconCtx.rx_precession_us;
Wayne Roberts 29:ad409c68c0a6 970 BeaconCtx.sendAt += BeaconCtx.tx_slot_offset * PING_SLOT_RESOLUTION_us;
Wayne Roberts 29:ad409c68c0a6 971 _tx_timeout.attach_us(&send_callback, BeaconCtx.sendAt);
Wayne Roberts 29:ad409c68c0a6 972 mac_printf("sendAt:%llu ", BeaconCtx.sendAt);
Wayne Roberts 29:ad409c68c0a6 973
Wayne Roberts 29:ad409c68c0a6 974 BeaconCtx.rx_setup_at += BEACON_INTERVAL_us;
Wayne Roberts 29:ad409c68c0a6 975 BeaconCtx.rx_setup_at += compensation;
Wayne Roberts 29:ad409c68c0a6 976
Wayne Roberts 29:ad409c68c0a6 977 BeaconCtx._timeout_rx.attach_us(&OnRxBeaconSetup, BeaconCtx.rx_setup_at);
Wayne Roberts 29:ad409c68c0a6 978 BeaconCtx._timeout_guard.attach_us(&guard_callback, BeaconCtx.rx_setup_at - BEACON_GUARD_us);
dudmuck 0:8f0d0ae0a077 979
dudmuck 0:8f0d0ae0a077 980 BeaconCtx.num_missed = 0;
dudmuck 0:8f0d0ae0a077 981
dudmuck 0:8f0d0ae0a077 982 MlmeIndication.MlmeIndication = MLME_BEACON;
dudmuck 0:8f0d0ae0a077 983 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED;
dudmuck 0:8f0d0ae0a077 984 LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
dudmuck 0:8f0d0ae0a077 985
dudmuck 0:8f0d0ae0a077 986 /* check beacon payload */
Wayne Roberts 29:ad409c68c0a6 987 uint16_t calc_crc = beacon_crc(Radio::radio.rx_buf, 4);
Wayne Roberts 29:ad409c68c0a6 988 uint16_t rx_crc = Radio::radio.rx_buf[4];
Wayne Roberts 29:ad409c68c0a6 989 rx_crc |= Radio::radio.rx_buf[5] << 8;
dudmuck 0:8f0d0ae0a077 990 if (rx_crc == calc_crc) {
Wayne Roberts 29:ad409c68c0a6 991 unsigned int rx = Radio::radio.rx_buf[0];
Wayne Roberts 29:ad409c68c0a6 992 rx |= Radio::radio.rx_buf[1] << 8;
Wayne Roberts 29:ad409c68c0a6 993 rx |= Radio::radio.rx_buf[2] << 16;
Wayne Roberts 29:ad409c68c0a6 994 rx |= Radio::radio.rx_buf[3] << 24;
dudmuck 10:00997daeb0c0 995 if (rx != 0) {
Wayne Roberts 29:ad409c68c0a6 996 //mac_printf("beacon payload:%08x\r\n", rx);
dudmuck 10:00997daeb0c0 997 McpsIndication.McpsIndication = MCPS_MULTICAST;
dudmuck 10:00997daeb0c0 998 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 999 McpsIndication.Buffer = Radio::radio.rx_buf;
dudmuck 10:00997daeb0c0 1000 McpsIndication.BufferSize = 4;
dudmuck 10:00997daeb0c0 1001 McpsIndication.RxData = true;
dudmuck 16:915815632c1f 1002 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
dudmuck 10:00997daeb0c0 1003 }
dudmuck 0:8f0d0ae0a077 1004 } else
Wayne Roberts 29:ad409c68c0a6 1005 mac_printf("calc_crc:%04x rx_crc:%04x\r\n", calc_crc, rx_crc);
Wayne Roberts 29:ad409c68c0a6 1006 } // ..rx_beacon()
Wayne Roberts 29:ad409c68c0a6 1007
Wayne Roberts 29:ad409c68c0a6 1008
Wayne Roberts 29:ad409c68c0a6 1009 #define JOIN_ACCEPT_MAX_SIZE 34
Wayne Roberts 29:ad409c68c0a6 1010 static void OnRadioRxDone(uint8_t size, float rssi, float snr )
dudmuck 0:8f0d0ae0a077 1011 {
Wayne Roberts 29:ad409c68c0a6 1012 uint8_t _jaDecrypted[JOIN_ACCEPT_MAX_SIZE];
dudmuck 0:8f0d0ae0a077 1013 LoRaMacHeader_t macHdr;
dudmuck 0:8f0d0ae0a077 1014 LoRaMacFrameCtrl_t fCtrl;
dudmuck 0:8f0d0ae0a077 1015 bool skipIndication = false;
dudmuck 0:8f0d0ae0a077 1016
dudmuck 0:8f0d0ae0a077 1017 uint8_t pktHeaderLen = 0;
dudmuck 0:8f0d0ae0a077 1018 uint32_t address = 0;
dudmuck 0:8f0d0ae0a077 1019 uint8_t appPayloadStartIndex = 0;
dudmuck 0:8f0d0ae0a077 1020 uint8_t port = 0xFF;
dudmuck 0:8f0d0ae0a077 1021 uint8_t frameLen = 0;
dudmuck 0:8f0d0ae0a077 1022 uint32_t mic = 0;
dudmuck 0:8f0d0ae0a077 1023 uint32_t micRx = 0;
dudmuck 0:8f0d0ae0a077 1024
dudmuck 0:8f0d0ae0a077 1025 uint16_t sequenceCounter = 0;
dudmuck 0:8f0d0ae0a077 1026 uint16_t sequenceCounterPrev = 0;
dudmuck 0:8f0d0ae0a077 1027 uint16_t sequenceCounterDiff = 0;
dudmuck 0:8f0d0ae0a077 1028 uint32_t downLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1029
dudmuck 0:8f0d0ae0a077 1030 MulticastParams_t *curMulticastParams = NULL;
dudmuck 0:8f0d0ae0a077 1031 uint8_t *nwkSKey = LoRaMacNwkSKey;
dudmuck 0:8f0d0ae0a077 1032 uint8_t *appSKey = LoRaMacAppSKey;
dudmuck 0:8f0d0ae0a077 1033
dudmuck 0:8f0d0ae0a077 1034 uint8_t multicast = 0;
dudmuck 0:8f0d0ae0a077 1035
dudmuck 0:8f0d0ae0a077 1036 bool isMicOk = false;
dudmuck 0:8f0d0ae0a077 1037
dudmuck 0:8f0d0ae0a077 1038 McpsConfirm.AckReceived = false;
dudmuck 0:8f0d0ae0a077 1039 McpsIndication.Rssi = rssi;
dudmuck 0:8f0d0ae0a077 1040 McpsIndication.Snr = snr;
dudmuck 0:8f0d0ae0a077 1041 McpsIndication.Port = 0;
dudmuck 0:8f0d0ae0a077 1042 McpsIndication.Multicast = 0;
dudmuck 0:8f0d0ae0a077 1043 McpsIndication.FramePending = 0;
dudmuck 0:8f0d0ae0a077 1044 McpsIndication.Buffer = NULL;
dudmuck 0:8f0d0ae0a077 1045 McpsIndication.BufferSize = 0;
dudmuck 0:8f0d0ae0a077 1046 McpsIndication.RxData = false;
dudmuck 0:8f0d0ae0a077 1047 McpsIndication.AckReceived = false;
dudmuck 0:8f0d0ae0a077 1048 McpsIndication.DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1049 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
dudmuck 0:8f0d0ae0a077 1050
Wayne Roberts 29:ad409c68c0a6 1051 Radio::Sleep( );
Wayne Roberts 29:ad409c68c0a6 1052
Wayne Roberts 29:ad409c68c0a6 1053 //mac_printf("OnRadioRxDone %u", size);
Wayne Roberts 29:ad409c68c0a6 1054 if (LoRaMacFlags.Bits.expecting_beacon) {
Wayne Roberts 29:ad409c68c0a6 1055 rx_beacon(size);
Wayne Roberts 29:ad409c68c0a6 1056 LoRaMacFlags.Bits.expecting_beacon = false;
dudmuck 0:8f0d0ae0a077 1057 return;
dudmuck 0:8f0d0ae0a077 1058 }
dudmuck 0:8f0d0ae0a077 1059
Wayne Roberts 29:ad409c68c0a6 1060 macHdr.Value = Radio::radio.rx_buf[pktHeaderLen++];
Wayne Roberts 29:ad409c68c0a6 1061 //mac_printf("mtype:%x\r\n", macHdr.Bits.MType);
dudmuck 0:8f0d0ae0a077 1062
dudmuck 0:8f0d0ae0a077 1063 switch( macHdr.Bits.MType )
dudmuck 0:8f0d0ae0a077 1064 {
dudmuck 0:8f0d0ae0a077 1065 case FRAME_TYPE_JOIN_ACCEPT:
Wayne Roberts 29:ad409c68c0a6 1066 if (LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
dudmuck 0:8f0d0ae0a077 1067 {
dudmuck 2:f2d9aa163652 1068 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_JOIN_ACCEPT;
dudmuck 0:8f0d0ae0a077 1069 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1070 return;
dudmuck 0:8f0d0ae0a077 1071 }
Wayne Roberts 29:ad409c68c0a6 1072 LoRaMacJoinDecrypt( Radio::radio.rx_buf + 1, size - 1, LoRaMacAppKey, &_jaDecrypted[1]);
Wayne Roberts 29:ad409c68c0a6 1073
Wayne Roberts 29:ad409c68c0a6 1074 _jaDecrypted[0] = macHdr.Value;
Wayne Roberts 29:ad409c68c0a6 1075
Wayne Roberts 29:ad409c68c0a6 1076 LoRaMacJoinComputeMic( _jaDecrypted, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic );
Wayne Roberts 29:ad409c68c0a6 1077
Wayne Roberts 29:ad409c68c0a6 1078 micRx |= ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN];
Wayne Roberts 29:ad409c68c0a6 1079 micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 1] << 8 );
Wayne Roberts 29:ad409c68c0a6 1080 micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 2] << 16 );
Wayne Roberts 29:ad409c68c0a6 1081 micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 3] << 24 );
dudmuck 0:8f0d0ae0a077 1082
dudmuck 0:8f0d0ae0a077 1083 if( micRx == mic )
dudmuck 0:8f0d0ae0a077 1084 {
Wayne Roberts 30:1c35c4f56e50 1085 uint32_t beaconDur;
Wayne Roberts 29:ad409c68c0a6 1086 LoRaMacJoinComputeSKeys( LoRaMacAppKey, _jaDecrypted + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
Wayne Roberts 29:ad409c68c0a6 1087
Wayne Roberts 29:ad409c68c0a6 1088 LoRaMacNetID = ( uint32_t )_jaDecrypted[4];
Wayne Roberts 29:ad409c68c0a6 1089 LoRaMacNetID |= ( ( uint32_t )_jaDecrypted[5] << 8 );
Wayne Roberts 29:ad409c68c0a6 1090 LoRaMacNetID |= ( ( uint32_t )_jaDecrypted[6] << 16 );
Wayne Roberts 29:ad409c68c0a6 1091
Wayne Roberts 29:ad409c68c0a6 1092 LoRaMacDevAddr = ( uint32_t )_jaDecrypted[7];
Wayne Roberts 29:ad409c68c0a6 1093 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[8] << 8 );
Wayne Roberts 29:ad409c68c0a6 1094 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[9] << 16 );
Wayne Roberts 29:ad409c68c0a6 1095 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[10] << 24 );
dudmuck 0:8f0d0ae0a077 1096
dudmuck 0:8f0d0ae0a077 1097 // DLSettings
Wayne Roberts 29:ad409c68c0a6 1098 LoRaMacParams.Rx1DrOffset = ( _jaDecrypted[11] >> 4 ) & 0x07;
Wayne Roberts 29:ad409c68c0a6 1099
Wayne Roberts 29:ad409c68c0a6 1100 LoRaMacParams.ReceiveDelay_us = ( _jaDecrypted[12] & 0x0F );
dudmuck 0:8f0d0ae0a077 1101 if( LoRaMacParams.ReceiveDelay_us == 0 )
dudmuck 0:8f0d0ae0a077 1102 LoRaMacParams.ReceiveDelay_us = RECEIVE_DELAY_us;
dudmuck 0:8f0d0ae0a077 1103 else
dudmuck 0:8f0d0ae0a077 1104 LoRaMacParams.ReceiveDelay_us *= 10;
dudmuck 0:8f0d0ae0a077 1105
Wayne Roberts 29:ad409c68c0a6 1106 uint16_t beaconTimingDelay = _jaDecrypted[13] & 0xff;
Wayne Roberts 29:ad409c68c0a6 1107 beaconTimingDelay |= _jaDecrypted[14] << 8;
Wayne Roberts 29:ad409c68c0a6 1108
Wayne Roberts 29:ad409c68c0a6 1109 mac_printf("%lx slots:%x (rxdelay %lu)", LoRaMacDevAddr, beaconTimingDelay, LoRaMacParams.ReceiveDelay_us);
Wayne Roberts 29:ad409c68c0a6 1110 {
Wayne Roberts 29:ad409c68c0a6 1111 unsigned us_to_beacon = ( PING_SLOT_RESOLUTION_us * beaconTimingDelay );
Wayne Roberts 29:ad409c68c0a6 1112 mac_printf(" us_to_beacon:%u ", us_to_beacon);
Wayne Roberts 29:ad409c68c0a6 1113 // time to beacon given as referenced to end of join request uplink
Wayne Roberts 29:ad409c68c0a6 1114 BeaconCtx.rx_setup_at = txDoneAt + us_to_beacon - PPM_BEACON_INTERVAL;
Wayne Roberts 29:ad409c68c0a6 1115 BeaconCtx._timeout_rx.attach_us(&OnRxBeaconSetup, BeaconCtx.rx_setup_at);
Wayne Roberts 29:ad409c68c0a6 1116 BeaconCtx._timeout_guard.attach_us(&guard_callback, BeaconCtx.rx_setup_at - BEACON_GUARD_us);
Wayne Roberts 29:ad409c68c0a6 1117
Wayne Roberts 29:ad409c68c0a6 1118 mac_printf("beaconIn:%llu\r\n", BeaconCtx.rx_setup_at - BeaconCtx._timeout_rx.read_us());
Wayne Roberts 29:ad409c68c0a6 1119 }
Wayne Roberts 29:ad409c68c0a6 1120
Wayne Roberts 29:ad409c68c0a6 1121 BeaconCtx.tx_slot_offset = _jaDecrypted[15];
Wayne Roberts 29:ad409c68c0a6 1122 BeaconCtx.tx_slot_offset |= _jaDecrypted[16] << 8;
Wayne Roberts 29:ad409c68c0a6 1123 BeaconCtx.periodicity_slots = _jaDecrypted[17];
Wayne Roberts 29:ad409c68c0a6 1124 BeaconCtx.periodicity_slots |= _jaDecrypted[18] << 8;
Wayne Roberts 29:ad409c68c0a6 1125
Wayne Roberts 30:1c35c4f56e50 1126 beaconDur = _jaDecrypted[22];
Wayne Roberts 30:1c35c4f56e50 1127 beaconDur <<= 8;
Wayne Roberts 30:1c35c4f56e50 1128 beaconDur |= _jaDecrypted[21];
Wayne Roberts 30:1c35c4f56e50 1129 beaconDur <<= 8;
Wayne Roberts 30:1c35c4f56e50 1130 beaconDur |= _jaDecrypted[20];
Wayne Roberts 30:1c35c4f56e50 1131 beaconDur <<= 8;
Wayne Roberts 30:1c35c4f56e50 1132 beaconDur |= _jaDecrypted[19];
Wayne Roberts 30:1c35c4f56e50 1133 BeaconCtx.beaconStartToRxDone = beaconDur + (rxLatencyFactorFromSF[SF_FROM_DR_(LORAMAC_DEFAULT_DATARATE)-FASTEST_SF] * BeaconCtx.symbol_period_us);
Wayne Roberts 30:1c35c4f56e50 1134
Wayne Roberts 30:1c35c4f56e50 1135
Wayne Roberts 29:ad409c68c0a6 1136 /* nowSlot: now vs previous beacon */
Wayne Roberts 29:ad409c68c0a6 1137 BeaconCtx.LastBeaconRx_us = BeaconCtx.rx_setup_at - BEACON_INTERVAL_us;
Wayne Roberts 29:ad409c68c0a6 1138 unsigned us_since_last_beacon = _rx_timeout.read_us() - BeaconCtx.LastBeaconRx_us;
Wayne Roberts 29:ad409c68c0a6 1139 unsigned nowSlot = us_since_last_beacon / PING_SLOT_RESOLUTION_us;
Wayne Roberts 29:ad409c68c0a6 1140 unsigned useSlot = BeaconCtx.tx_slot_offset;
Wayne Roberts 29:ad409c68c0a6 1141 while (useSlot < nowSlot)
Wayne Roberts 29:ad409c68c0a6 1142 useSlot += BeaconCtx.periodicity_slots;
Wayne Roberts 29:ad409c68c0a6 1143
Wayne Roberts 30:1c35c4f56e50 1144 mac_printf("beaconDur:0x%x (%u) useSlot:%u nowSlot:%u ", beaconDur, BeaconCtx.beaconStartToRxDone, useSlot, nowSlot);
Wayne Roberts 29:ad409c68c0a6 1145 BeaconCtx.sendAt = BeaconCtx.LastBeaconRx_us + (useSlot * PING_SLOT_RESOLUTION_us);
Wayne Roberts 29:ad409c68c0a6 1146 mac_printf("sendIn:%u\r\n", BeaconCtx.sendAt - _tx_timeout.read_us());
Wayne Roberts 29:ad409c68c0a6 1147 _tx_timeout.attach_us(send_callback, BeaconCtx.sendAt);
Wayne Roberts 29:ad409c68c0a6 1148 BeaconCtx.sendOpportunities = 0;
Wayne Roberts 29:ad409c68c0a6 1149
dudmuck 0:8f0d0ae0a077 1150 BeaconCtx.state = BEACON_STATE_FIRST_ACQ;
dudmuck 16:915815632c1f 1151 BeaconCtx.guard = false;
dudmuck 0:8f0d0ae0a077 1152 BeaconCtx.num_missed = 0;
dudmuck 0:8f0d0ae0a077 1153 BeaconCtx.rx_precession_us = 0;
Wayne Roberts 30:1c35c4f56e50 1154 BeaconCtx.num_consecutive_ok = 0;
Wayne Roberts 29:ad409c68c0a6 1155 BeaconCtx.last_BeaconRxTimerError_us = -PPM_BEACON_INTERVAL;
Wayne Roberts 29:ad409c68c0a6 1156 BeaconCtx.known_working_BeaconRxTimerError_us = -PPM_BEACON_INTERVAL;
Wayne Roberts 29:ad409c68c0a6 1157 /* first beacon reception needs to open for 30ms timing resolution */
dudmuck 32:ac904adfc842 1158 BeaconCtx.Precess_symbols = ceil((float)(TARGET_PRECESSION_us / BeaconCtx.symbol_period_us));
Wayne Roberts 30:1c35c4f56e50 1159 BeaconCtx.SymbolTimeout_us = PING_SLOT_RESOLUTION_us + (PPM_BEACON_INTERVAL * 4); // error unknown at start
Wayne Roberts 29:ad409c68c0a6 1160 BeaconCtx.nSymbsTimeout = BeaconCtx.SymbolTimeout_us / BeaconCtx.symbol_period_us;
Wayne Roberts 29:ad409c68c0a6 1161 if (BeaconCtx.nSymbsTimeout < MIN_SYMBOL_TIMEOUT)
Wayne Roberts 29:ad409c68c0a6 1162 BeaconCtx.nSymbsTimeout = MIN_SYMBOL_TIMEOUT;
Wayne Roberts 29:ad409c68c0a6 1163 else if (BeaconCtx.nSymbsTimeout > 255)
Wayne Roberts 29:ad409c68c0a6 1164 BeaconCtx.nSymbsTimeout = 255;
Wayne Roberts 29:ad409c68c0a6 1165 mac_printf("startSymbTo:%u ", BeaconCtx.nSymbsTimeout);
dudmuck 0:8f0d0ae0a077 1166
dudmuck 0:8f0d0ae0a077 1167 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 1168 LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = true;
dudmuck 0:8f0d0ae0a077 1169 LoRaMacParams.ChannelsDatarate_fixed = LoRaMacParamsDefaults.ChannelsDatarate_fixed;
dudmuck 0:8f0d0ae0a077 1170 }
dudmuck 0:8f0d0ae0a077 1171 else
dudmuck 0:8f0d0ae0a077 1172 {
dudmuck 0:8f0d0ae0a077 1173 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
Wayne Roberts 30:1c35c4f56e50 1174 mac_printf("join-mic-fail size:%u\r\n", size);
dudmuck 0:8f0d0ae0a077 1175 JoinRequestTrials = MaxJoinRequestTrials; // stop trying
dudmuck 0:8f0d0ae0a077 1176 }
dudmuck 16:915815632c1f 1177 LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
dudmuck 16:915815632c1f 1178 LoRaMacFlags.Bits.MlmeReq = 0; // MacMlmeConfirm() called
dudmuck 0:8f0d0ae0a077 1179 break;
dudmuck 0:8f0d0ae0a077 1180 case FRAME_TYPE_DATA_CONFIRMED_DOWN:
dudmuck 0:8f0d0ae0a077 1181 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
dudmuck 0:8f0d0ae0a077 1182 {
Wayne Roberts 29:ad409c68c0a6 1183 address = Radio::radio.rx_buf[pktHeaderLen++];
Wayne Roberts 29:ad409c68c0a6 1184 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 8 );
Wayne Roberts 29:ad409c68c0a6 1185 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 16 );
Wayne Roberts 29:ad409c68c0a6 1186 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 24 );
dudmuck 0:8f0d0ae0a077 1187
dudmuck 0:8f0d0ae0a077 1188 if( address != LoRaMacDevAddr )
dudmuck 0:8f0d0ae0a077 1189 {
dudmuck 0:8f0d0ae0a077 1190 curMulticastParams = MulticastChannels;
dudmuck 0:8f0d0ae0a077 1191 while( curMulticastParams != NULL )
dudmuck 0:8f0d0ae0a077 1192 {
dudmuck 0:8f0d0ae0a077 1193 if( address == curMulticastParams->Address )
dudmuck 0:8f0d0ae0a077 1194 {
dudmuck 0:8f0d0ae0a077 1195 multicast = 1;
dudmuck 0:8f0d0ae0a077 1196 nwkSKey = curMulticastParams->NwkSKey;
dudmuck 0:8f0d0ae0a077 1197 appSKey = curMulticastParams->AppSKey;
dudmuck 0:8f0d0ae0a077 1198 downLinkCounter = curMulticastParams->DownLinkCounter;
dudmuck 0:8f0d0ae0a077 1199 break;
dudmuck 0:8f0d0ae0a077 1200 }
dudmuck 0:8f0d0ae0a077 1201 curMulticastParams = curMulticastParams->Next;
dudmuck 0:8f0d0ae0a077 1202 }
dudmuck 0:8f0d0ae0a077 1203 if( multicast == 0 )
dudmuck 0:8f0d0ae0a077 1204 {
dudmuck 0:8f0d0ae0a077 1205 // We are not the destination of this frame.
dudmuck 0:8f0d0ae0a077 1206 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
dudmuck 0:8f0d0ae0a077 1207 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1208 return;
dudmuck 0:8f0d0ae0a077 1209 }
dudmuck 0:8f0d0ae0a077 1210 }
dudmuck 0:8f0d0ae0a077 1211 else
dudmuck 0:8f0d0ae0a077 1212 {
dudmuck 0:8f0d0ae0a077 1213 multicast = 0;
dudmuck 0:8f0d0ae0a077 1214 nwkSKey = LoRaMacNwkSKey;
dudmuck 0:8f0d0ae0a077 1215 appSKey = LoRaMacAppSKey;
dudmuck 0:8f0d0ae0a077 1216 downLinkCounter = DownLinkCounter;
dudmuck 0:8f0d0ae0a077 1217 }
dudmuck 0:8f0d0ae0a077 1218
Wayne Roberts 29:ad409c68c0a6 1219 fCtrl.Value = Radio::radio.rx_buf[pktHeaderLen++];
Wayne Roberts 29:ad409c68c0a6 1220
Wayne Roberts 29:ad409c68c0a6 1221 sequenceCounter = ( uint16_t )Radio::radio.rx_buf[pktHeaderLen++];
Wayne Roberts 29:ad409c68c0a6 1222 sequenceCounter |= ( uint16_t )Radio::radio.rx_buf[pktHeaderLen++] << 8;
dudmuck 0:8f0d0ae0a077 1223
dudmuck 0:8f0d0ae0a077 1224 appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
dudmuck 0:8f0d0ae0a077 1225
Wayne Roberts 29:ad409c68c0a6 1226 micRx |= ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN];
Wayne Roberts 29:ad409c68c0a6 1227 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 1] << 8 );
Wayne Roberts 29:ad409c68c0a6 1228 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 2] << 16 );
Wayne Roberts 29:ad409c68c0a6 1229 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 3] << 24 );
dudmuck 0:8f0d0ae0a077 1230
dudmuck 0:8f0d0ae0a077 1231 sequenceCounterPrev = ( uint16_t )downLinkCounter;
dudmuck 0:8f0d0ae0a077 1232 sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev );
dudmuck 0:8f0d0ae0a077 1233
dudmuck 0:8f0d0ae0a077 1234 if( sequenceCounterDiff < ( 1 << 15 ) )
dudmuck 0:8f0d0ae0a077 1235 {
dudmuck 0:8f0d0ae0a077 1236 downLinkCounter += sequenceCounterDiff;
Wayne Roberts 29:ad409c68c0a6 1237 LoRaMacComputeMic( Radio::radio.rx_buf, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
dudmuck 0:8f0d0ae0a077 1238 if( micRx == mic )
dudmuck 0:8f0d0ae0a077 1239 {
dudmuck 0:8f0d0ae0a077 1240 isMicOk = true;
dudmuck 0:8f0d0ae0a077 1241 }
dudmuck 0:8f0d0ae0a077 1242 }
dudmuck 0:8f0d0ae0a077 1243 else
dudmuck 0:8f0d0ae0a077 1244 {
dudmuck 0:8f0d0ae0a077 1245 // check for sequence roll-over
dudmuck 0:8f0d0ae0a077 1246 uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff;
Wayne Roberts 29:ad409c68c0a6 1247 LoRaMacComputeMic( Radio::radio.rx_buf, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic );
dudmuck 0:8f0d0ae0a077 1248 if( micRx == mic )
dudmuck 0:8f0d0ae0a077 1249 {
dudmuck 0:8f0d0ae0a077 1250 isMicOk = true;
dudmuck 0:8f0d0ae0a077 1251 downLinkCounter = downLinkCounterTmp;
dudmuck 0:8f0d0ae0a077 1252 }
dudmuck 0:8f0d0ae0a077 1253 }
dudmuck 0:8f0d0ae0a077 1254
dudmuck 0:8f0d0ae0a077 1255 // Check for a the maximum allowed counter difference
dudmuck 0:8f0d0ae0a077 1256 if( sequenceCounterDiff >= MAX_FCNT_GAP )
dudmuck 0:8f0d0ae0a077 1257 {
dudmuck 0:8f0d0ae0a077 1258 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
dudmuck 0:8f0d0ae0a077 1259 McpsIndication.DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1260 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1261 return;
dudmuck 0:8f0d0ae0a077 1262 }
dudmuck 0:8f0d0ae0a077 1263
dudmuck 0:8f0d0ae0a077 1264 if( isMicOk == true )
dudmuck 0:8f0d0ae0a077 1265 {
dudmuck 0:8f0d0ae0a077 1266 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1267 McpsIndication.Multicast = multicast;
dudmuck 0:8f0d0ae0a077 1268 McpsIndication.FramePending = fCtrl.Bits.FPending;
dudmuck 0:8f0d0ae0a077 1269 McpsIndication.Buffer = NULL;
dudmuck 0:8f0d0ae0a077 1270 McpsIndication.BufferSize = 0;
dudmuck 0:8f0d0ae0a077 1271 McpsIndication.DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1272
dudmuck 0:8f0d0ae0a077 1273 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1274
dudmuck 0:8f0d0ae0a077 1275 MacCommandsBufferToRepeatIndex = 0;
dudmuck 0:8f0d0ae0a077 1276
dudmuck 0:8f0d0ae0a077 1277 // Update 32 bits downlink counter
dudmuck 0:8f0d0ae0a077 1278 if( multicast == 1 )
dudmuck 0:8f0d0ae0a077 1279 {
dudmuck 0:8f0d0ae0a077 1280 McpsIndication.McpsIndication = MCPS_MULTICAST;
dudmuck 0:8f0d0ae0a077 1281
dudmuck 0:8f0d0ae0a077 1282 if( ( curMulticastParams->DownLinkCounter == downLinkCounter ) &&
dudmuck 0:8f0d0ae0a077 1283 ( curMulticastParams->DownLinkCounter != 0 ) )
dudmuck 0:8f0d0ae0a077 1284 {
dudmuck 0:8f0d0ae0a077 1285 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
dudmuck 0:8f0d0ae0a077 1286 McpsIndication.DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1287 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1288 return;
dudmuck 0:8f0d0ae0a077 1289 }
dudmuck 0:8f0d0ae0a077 1290 curMulticastParams->DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1291 }
dudmuck 0:8f0d0ae0a077 1292 else
dudmuck 0:8f0d0ae0a077 1293 {
dudmuck 0:8f0d0ae0a077 1294 if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
dudmuck 0:8f0d0ae0a077 1295 {
Wayne Roberts 29:ad409c68c0a6 1296 LoRaMacFlags.Bits.SrvAckRequested = true;
dudmuck 0:8f0d0ae0a077 1297 McpsIndication.McpsIndication = MCPS_CONFIRMED;
dudmuck 0:8f0d0ae0a077 1298
dudmuck 0:8f0d0ae0a077 1299 if( ( DownLinkCounter == downLinkCounter ) &&
dudmuck 0:8f0d0ae0a077 1300 ( DownLinkCounter != 0 ) )
dudmuck 0:8f0d0ae0a077 1301 {
dudmuck 0:8f0d0ae0a077 1302 // Duplicated confirmed downlink. Skip indication.
dudmuck 0:8f0d0ae0a077 1303 // In this case, the MAC layer shall accept the MAC commands
dudmuck 0:8f0d0ae0a077 1304 // which are included in the downlink retransmission.
dudmuck 0:8f0d0ae0a077 1305 // It should not provide the same frame to the application
dudmuck 0:8f0d0ae0a077 1306 // layer again.
dudmuck 0:8f0d0ae0a077 1307 skipIndication = true;
dudmuck 0:8f0d0ae0a077 1308 }
dudmuck 0:8f0d0ae0a077 1309 }
dudmuck 0:8f0d0ae0a077 1310 else
dudmuck 0:8f0d0ae0a077 1311 {
Wayne Roberts 29:ad409c68c0a6 1312 LoRaMacFlags.Bits.SrvAckRequested = false;
dudmuck 0:8f0d0ae0a077 1313 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
dudmuck 0:8f0d0ae0a077 1314
dudmuck 0:8f0d0ae0a077 1315 if( ( DownLinkCounter == downLinkCounter ) &&
dudmuck 0:8f0d0ae0a077 1316 ( DownLinkCounter != 0 ) )
dudmuck 0:8f0d0ae0a077 1317 {
dudmuck 0:8f0d0ae0a077 1318 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
dudmuck 0:8f0d0ae0a077 1319 McpsIndication.DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1320 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1321 return;
dudmuck 0:8f0d0ae0a077 1322 }
dudmuck 0:8f0d0ae0a077 1323 }
dudmuck 0:8f0d0ae0a077 1324 DownLinkCounter = downLinkCounter;
dudmuck 0:8f0d0ae0a077 1325 }
dudmuck 0:8f0d0ae0a077 1326
dudmuck 0:8f0d0ae0a077 1327 // This must be done before parsing the payload and the MAC commands.
dudmuck 0:8f0d0ae0a077 1328 // We need to reset the MacCommandsBufferIndex here, since we need
dudmuck 0:8f0d0ae0a077 1329 // to take retransmissions and repititions into account. Error cases
dudmuck 0:8f0d0ae0a077 1330 // will be handled in function OnMacStateCheckTimerEvent.
dudmuck 0:8f0d0ae0a077 1331 if( McpsConfirm.McpsRequest == MCPS_CONFIRMED )
dudmuck 0:8f0d0ae0a077 1332 {
dudmuck 0:8f0d0ae0a077 1333 if( fCtrl.Bits.Ack == 1 )
dudmuck 0:8f0d0ae0a077 1334 {// Reset MacCommandsBufferIndex when we have received an ACK.
dudmuck 0:8f0d0ae0a077 1335 MacCommandsBufferIndex = 0;
dudmuck 0:8f0d0ae0a077 1336 }
dudmuck 0:8f0d0ae0a077 1337 }
dudmuck 0:8f0d0ae0a077 1338 else
dudmuck 0:8f0d0ae0a077 1339 {// Reset the variable if we have received any valid frame.
dudmuck 0:8f0d0ae0a077 1340 MacCommandsBufferIndex = 0;
dudmuck 0:8f0d0ae0a077 1341 }
dudmuck 0:8f0d0ae0a077 1342
dudmuck 0:8f0d0ae0a077 1343 // Process payload and MAC commands
dudmuck 0:8f0d0ae0a077 1344 if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
dudmuck 0:8f0d0ae0a077 1345 {
Wayne Roberts 29:ad409c68c0a6 1346 port = Radio::radio.rx_buf[appPayloadStartIndex++];
dudmuck 0:8f0d0ae0a077 1347 frameLen = ( size - 4 ) - appPayloadStartIndex;
dudmuck 0:8f0d0ae0a077 1348
dudmuck 0:8f0d0ae0a077 1349 McpsIndication.Port = port;
dudmuck 0:8f0d0ae0a077 1350
dudmuck 0:8f0d0ae0a077 1351 if( port == 0 )
dudmuck 0:8f0d0ae0a077 1352 {
dudmuck 0:8f0d0ae0a077 1353 // Only allow frames which do not have fOpts
dudmuck 0:8f0d0ae0a077 1354 if( fCtrl.Bits.FOptsLen == 0 )
dudmuck 0:8f0d0ae0a077 1355 {
Wayne Roberts 29:ad409c68c0a6 1356 uint8_t macDecrypt[16];
Wayne Roberts 29:ad409c68c0a6 1357 LoRaMacPayloadDecrypt( Radio::radio.rx_buf + appPayloadStartIndex,
dudmuck 0:8f0d0ae0a077 1358 frameLen,
dudmuck 0:8f0d0ae0a077 1359 nwkSKey,
dudmuck 0:8f0d0ae0a077 1360 address,
dudmuck 0:8f0d0ae0a077 1361 DOWN_LINK,
dudmuck 0:8f0d0ae0a077 1362 downLinkCounter,
Wayne Roberts 29:ad409c68c0a6 1363 macDecrypt);
dudmuck 0:8f0d0ae0a077 1364
dudmuck 0:8f0d0ae0a077 1365 // Decode frame payload MAC commands
Wayne Roberts 29:ad409c68c0a6 1366 ProcessMacCommands( macDecrypt, 0, frameLen, snr );
dudmuck 0:8f0d0ae0a077 1367 }
dudmuck 0:8f0d0ae0a077 1368 else
dudmuck 0:8f0d0ae0a077 1369 {
dudmuck 0:8f0d0ae0a077 1370 skipIndication = true;
dudmuck 0:8f0d0ae0a077 1371 }
dudmuck 0:8f0d0ae0a077 1372 }
dudmuck 0:8f0d0ae0a077 1373 else
dudmuck 0:8f0d0ae0a077 1374 {
dudmuck 0:8f0d0ae0a077 1375 if( fCtrl.Bits.FOptsLen > 0 )
dudmuck 0:8f0d0ae0a077 1376 {
dudmuck 0:8f0d0ae0a077 1377 // Decode Options field MAC commands. Omit the fPort.
Wayne Roberts 29:ad409c68c0a6 1378 ProcessMacCommands( Radio::radio.rx_buf, 8, appPayloadStartIndex - 1, snr );
dudmuck 0:8f0d0ae0a077 1379 }
dudmuck 0:8f0d0ae0a077 1380
Wayne Roberts 29:ad409c68c0a6 1381 LoRaMacPayloadDecrypt( Radio::radio.rx_buf + appPayloadStartIndex,
dudmuck 0:8f0d0ae0a077 1382 frameLen,
dudmuck 0:8f0d0ae0a077 1383 appSKey,
dudmuck 0:8f0d0ae0a077 1384 address,
dudmuck 0:8f0d0ae0a077 1385 DOWN_LINK,
dudmuck 0:8f0d0ae0a077 1386 downLinkCounter,
Wayne Roberts 29:ad409c68c0a6 1387 rxFRMPayload);
dudmuck 0:8f0d0ae0a077 1388
dudmuck 0:8f0d0ae0a077 1389 if( skipIndication == false )
dudmuck 0:8f0d0ae0a077 1390 {
Wayne Roberts 29:ad409c68c0a6 1391 McpsIndication.Buffer = rxFRMPayload;
dudmuck 0:8f0d0ae0a077 1392 McpsIndication.BufferSize = frameLen;
dudmuck 0:8f0d0ae0a077 1393 McpsIndication.RxData = true;
dudmuck 0:8f0d0ae0a077 1394 }
dudmuck 0:8f0d0ae0a077 1395 }
dudmuck 0:8f0d0ae0a077 1396 }
dudmuck 0:8f0d0ae0a077 1397 else
dudmuck 0:8f0d0ae0a077 1398 {
dudmuck 0:8f0d0ae0a077 1399 if( fCtrl.Bits.FOptsLen > 0 )
dudmuck 0:8f0d0ae0a077 1400 {
dudmuck 0:8f0d0ae0a077 1401 // Decode Options field MAC commands
Wayne Roberts 29:ad409c68c0a6 1402 ProcessMacCommands( Radio::radio.rx_buf, 8, appPayloadStartIndex, snr );
dudmuck 0:8f0d0ae0a077 1403 }
dudmuck 0:8f0d0ae0a077 1404 }
dudmuck 0:8f0d0ae0a077 1405
dudmuck 0:8f0d0ae0a077 1406 if( skipIndication == false )
dudmuck 0:8f0d0ae0a077 1407 {
dudmuck 0:8f0d0ae0a077 1408 // Check if the frame is an acknowledgement
dudmuck 0:8f0d0ae0a077 1409 if( fCtrl.Bits.Ack == 1 )
dudmuck 0:8f0d0ae0a077 1410 {
dudmuck 0:8f0d0ae0a077 1411 McpsConfirm.AckReceived = true;
dudmuck 0:8f0d0ae0a077 1412 McpsIndication.AckReceived = true;
dudmuck 0:8f0d0ae0a077 1413
dudmuck 0:8f0d0ae0a077 1414 // Stop the AckTimeout timer as no more retransmissions
dudmuck 0:8f0d0ae0a077 1415 // are needed.
dudmuck 0:8f0d0ae0a077 1416 }
dudmuck 0:8f0d0ae0a077 1417 else
dudmuck 0:8f0d0ae0a077 1418 {
dudmuck 0:8f0d0ae0a077 1419 McpsConfirm.AckReceived = false;
dudmuck 0:8f0d0ae0a077 1420 }
dudmuck 0:8f0d0ae0a077 1421 }
dudmuck 0:8f0d0ae0a077 1422 // Provide always an indication, skip the callback to the user application,
dudmuck 0:8f0d0ae0a077 1423 // in case of a confirmed downlink retransmission.
dudmuck 0:8f0d0ae0a077 1424 LoRaMacFlags.Bits.McpsInd = 1;
dudmuck 0:8f0d0ae0a077 1425 LoRaMacFlags.Bits.McpsIndSkip = skipIndication;
dudmuck 0:8f0d0ae0a077 1426 }
dudmuck 0:8f0d0ae0a077 1427 else
dudmuck 0:8f0d0ae0a077 1428 {
dudmuck 0:8f0d0ae0a077 1429 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
dudmuck 5:c108560af4c3 1430 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
dudmuck 0:8f0d0ae0a077 1431 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1432 return;
dudmuck 0:8f0d0ae0a077 1433 }
dudmuck 0:8f0d0ae0a077 1434 }
dudmuck 0:8f0d0ae0a077 1435 break;
dudmuck 0:8f0d0ae0a077 1436 case FRAME_TYPE_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 1437 {
dudmuck 0:8f0d0ae0a077 1438 McpsIndication.McpsIndication = MCPS_PROPRIETARY;
dudmuck 0:8f0d0ae0a077 1439 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 1440 McpsIndication.Buffer = Radio::radio.rx_buf;
dudmuck 0:8f0d0ae0a077 1441 McpsIndication.BufferSize = size - pktHeaderLen;
dudmuck 0:8f0d0ae0a077 1442
dudmuck 0:8f0d0ae0a077 1443 LoRaMacFlags.Bits.McpsInd = 1;
dudmuck 0:8f0d0ae0a077 1444 break;
dudmuck 0:8f0d0ae0a077 1445 }
dudmuck 0:8f0d0ae0a077 1446 default:
dudmuck 2:f2d9aa163652 1447 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE;
dudmuck 5:c108560af4c3 1448 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE;
Wayne Roberts 29:ad409c68c0a6 1449 mac_printf("%d:macHdr:%02x(%d,%d) ", size, macHdr.Value, rssi, snr);
dudmuck 0:8f0d0ae0a077 1450 PrepareRxDoneAbort( );
dudmuck 0:8f0d0ae0a077 1451 break;
dudmuck 0:8f0d0ae0a077 1452 }
dudmuck 0:8f0d0ae0a077 1453 LoRaMacFlags.Bits.MacDone = 1;
dudmuck 0:8f0d0ae0a077 1454
dudmuck 16:915815632c1f 1455 application_callbacks();
dudmuck 16:915815632c1f 1456
Wayne Roberts 29:ad409c68c0a6 1457 } // ..OnRadioRxDone()
dudmuck 16:915815632c1f 1458
dudmuck 0:8f0d0ae0a077 1459 static void OnRadioTxTimeout( void )
dudmuck 0:8f0d0ae0a077 1460 {
Wayne Roberts 29:ad409c68c0a6 1461 Radio::Sleep( );
dudmuck 0:8f0d0ae0a077 1462
dudmuck 0:8f0d0ae0a077 1463 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 1464 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 1465 LoRaMacFlags.Bits.MacDone = 1;
dudmuck 0:8f0d0ae0a077 1466 }
dudmuck 0:8f0d0ae0a077 1467
dudmuck 0:8f0d0ae0a077 1468 static void OnRadioRxError( void )
dudmuck 0:8f0d0ae0a077 1469 {
Wayne Roberts 29:ad409c68c0a6 1470 Radio::Sleep( );
Wayne Roberts 29:ad409c68c0a6 1471
Wayne Roberts 29:ad409c68c0a6 1472 if (LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 1473 {
dudmuck 0:8f0d0ae0a077 1474 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR;
dudmuck 0:8f0d0ae0a077 1475 }
dudmuck 0:8f0d0ae0a077 1476 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR;
dudmuck 0:8f0d0ae0a077 1477
Wayne Roberts 29:ad409c68c0a6 1478 LoRaMacFlags.Bits.MacDone = 1;
dudmuck 0:8f0d0ae0a077 1479 }
dudmuck 0:8f0d0ae0a077 1480
dudmuck 16:915815632c1f 1481 static void
dudmuck 16:915815632c1f 1482 join_send()
dudmuck 16:915815632c1f 1483 {
Wayne Roberts 29:ad409c68c0a6 1484 LoRaMacFlags.Bits.join_send = 1;
dudmuck 20:42839629a5dc 1485 }
dudmuck 20:42839629a5dc 1486
dudmuck 25:fed9d5b77183 1487 static void ScheduleTx( void )
dudmuck 25:fed9d5b77183 1488 {
Wayne Roberts 29:ad409c68c0a6 1489 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
Wayne Roberts 29:ad409c68c0a6 1490 LoRaMacFlags.Bits.send = 1; // immediately send join asychronously
dudmuck 25:fed9d5b77183 1491 else
dudmuck 25:fed9d5b77183 1492 LoRaMacFlags.Bits.uplink_pending = 1; // send synchronously
dudmuck 25:fed9d5b77183 1493 }
dudmuck 25:fed9d5b77183 1494
dudmuck 20:42839629a5dc 1495 static void
dudmuck 20:42839629a5dc 1496 join_send_bh()
dudmuck 20:42839629a5dc 1497 {
dudmuck 16:915815632c1f 1498 if (JoinRequestTrials < MaxJoinRequestTrials) {
dudmuck 16:915815632c1f 1499 LoRaMacHeader_t macHdr;
dudmuck 16:915815632c1f 1500 LoRaMacFrameCtrl_t fCtrl;
Wayne Roberts 29:ad409c68c0a6 1501
dudmuck 16:915815632c1f 1502 if (++Channel == LORA_MAX_NB_CHANNELS)
dudmuck 16:915815632c1f 1503 Channel = 0;
Wayne Roberts 29:ad409c68c0a6 1504 mac_printf("<join-ch%u>", Channel);
Wayne Roberts 29:ad409c68c0a6 1505
dudmuck 16:915815632c1f 1506 macHdr.Value = 0;
dudmuck 16:915815632c1f 1507 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
Wayne Roberts 29:ad409c68c0a6 1508
dudmuck 16:915815632c1f 1509 fCtrl.Value = 0;
dudmuck 16:915815632c1f 1510 fCtrl.Bits.Adr = 0;
Wayne Roberts 29:ad409c68c0a6 1511
dudmuck 16:915815632c1f 1512 /* In case of join request retransmissions, the stack must prepare
dudmuck 16:915815632c1f 1513 * the frame again, because the network server keeps track of the random
dudmuck 16:915815632c1f 1514 * LoRaMacDevNonce values to prevent reply attacks. */
dudmuck 16:915815632c1f 1515 PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 );
Wayne Roberts 29:ad409c68c0a6 1516
dudmuck 16:915815632c1f 1517 ScheduleTx();
dudmuck 16:915815632c1f 1518 } else {
dudmuck 16:915815632c1f 1519 MlmeConfirm.MlmeRequest = MLME_JOIN;
dudmuck 16:915815632c1f 1520 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
dudmuck 16:915815632c1f 1521 LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
dudmuck 16:915815632c1f 1522 }
Wayne Roberts 29:ad409c68c0a6 1523 } // ..join_send_bh()
dudmuck 16:915815632c1f 1524
dudmuck 0:8f0d0ae0a077 1525 static void OnRadioRxTimeout( void )
dudmuck 0:8f0d0ae0a077 1526 {
Wayne Roberts 29:ad409c68c0a6 1527 Radio::Sleep( );
Wayne Roberts 29:ad409c68c0a6 1528
Wayne Roberts 29:ad409c68c0a6 1529 if (LoRaMacFlags.Bits.expecting_beacon) {
Wayne Roberts 29:ad409c68c0a6 1530 float ourErrSecs = BeaconCtx.known_working_BeaconRxTimerError_us / 1000000.0;
dudmuck 0:8f0d0ae0a077 1531
Wayne Roberts 29:ad409c68c0a6 1532 LoRaMacFlags.Bits.expecting_beacon = false;
Wayne Roberts 29:ad409c68c0a6 1533
Wayne Roberts 29:ad409c68c0a6 1534 BeaconCtx.rx_setup_at += BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us;
Wayne Roberts 29:ad409c68c0a6 1535 BeaconCtx.rx_setup_at -= (PPM_BEACON_INTERVAL / 4);
Wayne Roberts 30:1c35c4f56e50 1536 us_to_nSymbTimeout(BeaconCtx.SymbolTimeout_us + PPM_BEACON_INTERVAL);
Wayne Roberts 30:1c35c4f56e50 1537 mac_printf("beacon timeout ourErr:%f SymbTo:%u(%uus)\r\n", ourErrSecs, BeaconCtx.nSymbsTimeout, BeaconCtx.SymbolTimeout_us);
Wayne Roberts 29:ad409c68c0a6 1538
Wayne Roberts 29:ad409c68c0a6 1539 BeaconCtx._timeout_rx.attach_us(&OnRxBeaconSetup, BeaconCtx.rx_setup_at);
Wayne Roberts 29:ad409c68c0a6 1540 BeaconCtx._timeout_guard.attach_us(&guard_callback, BeaconCtx.rx_setup_at - BEACON_GUARD_us);
Wayne Roberts 29:ad409c68c0a6 1541
Wayne Roberts 29:ad409c68c0a6 1542 if (++BeaconCtx.num_missed > BEACONS_MISSED_LIMIT) {
Wayne Roberts 29:ad409c68c0a6 1543 LoRaMacFlags.Bits.reJoin = 1;
Wayne Roberts 29:ad409c68c0a6 1544 } else {
Wayne Roberts 29:ad409c68c0a6 1545 MlmeIndication.MlmeIndication = MLME_BEACON;
Wayne Roberts 29:ad409c68c0a6 1546 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_BEACON_LOST;
Wayne Roberts 29:ad409c68c0a6 1547 LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
Wayne Roberts 29:ad409c68c0a6 1548 }
Wayne Roberts 29:ad409c68c0a6 1549
Wayne Roberts 29:ad409c68c0a6 1550 BeaconCtx.sendAt = BeaconCtx.LastBeaconRx_us + ((BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us) * BeaconCtx.num_missed);
Wayne Roberts 29:ad409c68c0a6 1551 BeaconCtx.sendAt += BeaconCtx.tx_slot_offset * PING_SLOT_RESOLUTION_us;
Wayne Roberts 29:ad409c68c0a6 1552 _tx_timeout.attach_us(&send_callback, BeaconCtx.sendAt);
Wayne Roberts 29:ad409c68c0a6 1553
Wayne Roberts 30:1c35c4f56e50 1554 BeaconCtx.num_consecutive_ok = 0;
dudmuck 16:915815632c1f 1555 } else {
dudmuck 25:fed9d5b77183 1556 if (LoRaMacFlags.Bits.MlmeReq && ( MlmeConfirm.MlmeRequest == MLME_JOIN )) {
dudmuck 25:fed9d5b77183 1557 /* no join accept received: join retry */
Wayne Roberts 29:ad409c68c0a6 1558 _tx_timeout.attach_us(&join_send, _tx_timeout.read_us() + (JoinRequestTrials*20000) + randr(0, 70000));
dudmuck 25:fed9d5b77183 1559 }
dudmuck 0:8f0d0ae0a077 1560 }
dudmuck 0:8f0d0ae0a077 1561
Wayne Roberts 29:ad409c68c0a6 1562 if (LoRaMacFlags.Bits.NodeAckRequested)
dudmuck 0:8f0d0ae0a077 1563 {
dudmuck 0:8f0d0ae0a077 1564 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 1565 }
dudmuck 0:8f0d0ae0a077 1566 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
dudmuck 0:8f0d0ae0a077 1567 LoRaMacFlags.Bits.MacDone = 1;
Wayne Roberts 29:ad409c68c0a6 1568
dudmuck 16:915815632c1f 1569 application_callbacks();
dudmuck 1:53c30224eda8 1570 } // ..OnRadioRxTimeout();
dudmuck 0:8f0d0ae0a077 1571
dudmuck 0:8f0d0ae0a077 1572 static void OnAckTimeoutTimerEvent( void )
dudmuck 0:8f0d0ae0a077 1573 {
dudmuck 0:8f0d0ae0a077 1574 }
dudmuck 0:8f0d0ae0a077 1575
dudmuck 0:8f0d0ae0a077 1576 static bool ValueInRange( int8_t value, int8_t min, int8_t max )
dudmuck 0:8f0d0ae0a077 1577 {
dudmuck 0:8f0d0ae0a077 1578 if( ( value >= min ) && ( value <= max ) )
dudmuck 0:8f0d0ae0a077 1579 {
dudmuck 0:8f0d0ae0a077 1580 return true;
dudmuck 0:8f0d0ae0a077 1581 }
dudmuck 0:8f0d0ae0a077 1582 return false;
dudmuck 0:8f0d0ae0a077 1583 }
dudmuck 0:8f0d0ae0a077 1584
dudmuck 0:8f0d0ae0a077 1585 static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
dudmuck 0:8f0d0ae0a077 1586 {
dudmuck 0:8f0d0ae0a077 1587 LoRaMacStatus_t status = LORAMAC_STATUS_BUSY;
dudmuck 0:8f0d0ae0a077 1588 // The maximum buffer length must take MAC commands to re-send into account.
dudmuck 0:8f0d0ae0a077 1589 uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex;
dudmuck 0:8f0d0ae0a077 1590
dudmuck 0:8f0d0ae0a077 1591 switch( cmd )
dudmuck 0:8f0d0ae0a077 1592 {
dudmuck 0:8f0d0ae0a077 1593 case MOTE_MAC_LINK_CHECK_REQ:
dudmuck 0:8f0d0ae0a077 1594 if( MacCommandsBufferIndex < bufLen )
dudmuck 0:8f0d0ae0a077 1595 {
dudmuck 0:8f0d0ae0a077 1596 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
dudmuck 0:8f0d0ae0a077 1597 // No payload for this command
dudmuck 0:8f0d0ae0a077 1598 status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1599 }
dudmuck 0:8f0d0ae0a077 1600 break;
dudmuck 0:8f0d0ae0a077 1601 case MOTE_MAC_RX_PARAM_SETUP_ANS:
dudmuck 0:8f0d0ae0a077 1602 if( MacCommandsBufferIndex < ( bufLen - 1 ) )
dudmuck 0:8f0d0ae0a077 1603 {
dudmuck 0:8f0d0ae0a077 1604 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
dudmuck 0:8f0d0ae0a077 1605 // Status: Datarate ACK, Channel ACK
dudmuck 0:8f0d0ae0a077 1606 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
dudmuck 0:8f0d0ae0a077 1607 status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1608 }
dudmuck 0:8f0d0ae0a077 1609 break;
dudmuck 0:8f0d0ae0a077 1610 case MOTE_MAC_DEV_STATUS_ANS:
dudmuck 0:8f0d0ae0a077 1611 if( MacCommandsBufferIndex < ( bufLen - 2 ) )
dudmuck 0:8f0d0ae0a077 1612 {
dudmuck 0:8f0d0ae0a077 1613 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
dudmuck 0:8f0d0ae0a077 1614 // 1st byte Battery
dudmuck 0:8f0d0ae0a077 1615 // 2nd byte Margin
dudmuck 0:8f0d0ae0a077 1616 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
dudmuck 0:8f0d0ae0a077 1617 MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
dudmuck 0:8f0d0ae0a077 1618 status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1619 }
dudmuck 0:8f0d0ae0a077 1620 break;
dudmuck 0:8f0d0ae0a077 1621 case MOTE_MAC_RX_TIMING_SETUP_ANS:
dudmuck 0:8f0d0ae0a077 1622 if( MacCommandsBufferIndex < bufLen )
dudmuck 0:8f0d0ae0a077 1623 {
dudmuck 0:8f0d0ae0a077 1624 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
dudmuck 0:8f0d0ae0a077 1625 // No payload for this answer
dudmuck 0:8f0d0ae0a077 1626 status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1627 }
dudmuck 0:8f0d0ae0a077 1628 break;
dudmuck 0:8f0d0ae0a077 1629 default:
dudmuck 0:8f0d0ae0a077 1630 return LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 1631 }
dudmuck 0:8f0d0ae0a077 1632 if( status == LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 1633 {
dudmuck 0:8f0d0ae0a077 1634 MacCommandsInNextTx = true;
dudmuck 0:8f0d0ae0a077 1635 }
dudmuck 0:8f0d0ae0a077 1636 return status;
dudmuck 0:8f0d0ae0a077 1637 }
dudmuck 0:8f0d0ae0a077 1638
dudmuck 0:8f0d0ae0a077 1639 static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut )
dudmuck 0:8f0d0ae0a077 1640 {
dudmuck 0:8f0d0ae0a077 1641 uint8_t i = 0;
dudmuck 0:8f0d0ae0a077 1642 uint8_t cmdCount = 0;
dudmuck 0:8f0d0ae0a077 1643
dudmuck 0:8f0d0ae0a077 1644 if( ( cmdBufIn == NULL ) || ( cmdBufOut == NULL ) )
dudmuck 0:8f0d0ae0a077 1645 {
dudmuck 0:8f0d0ae0a077 1646 return 0;
dudmuck 0:8f0d0ae0a077 1647 }
dudmuck 0:8f0d0ae0a077 1648
dudmuck 0:8f0d0ae0a077 1649 for( i = 0; i < length; i++ )
dudmuck 0:8f0d0ae0a077 1650 {
dudmuck 0:8f0d0ae0a077 1651 switch( cmdBufIn[i] )
dudmuck 0:8f0d0ae0a077 1652 {
dudmuck 0:8f0d0ae0a077 1653 // STICKY
dudmuck 0:8f0d0ae0a077 1654 case MOTE_MAC_RX_PARAM_SETUP_ANS:
dudmuck 0:8f0d0ae0a077 1655 {
dudmuck 0:8f0d0ae0a077 1656 cmdBufOut[cmdCount++] = cmdBufIn[i++];
dudmuck 0:8f0d0ae0a077 1657 cmdBufOut[cmdCount++] = cmdBufIn[i];
dudmuck 0:8f0d0ae0a077 1658 break;
dudmuck 0:8f0d0ae0a077 1659 }
dudmuck 0:8f0d0ae0a077 1660 case MOTE_MAC_RX_TIMING_SETUP_ANS:
dudmuck 0:8f0d0ae0a077 1661 {
dudmuck 0:8f0d0ae0a077 1662 cmdBufOut[cmdCount++] = cmdBufIn[i];
dudmuck 0:8f0d0ae0a077 1663 break;
dudmuck 0:8f0d0ae0a077 1664 }
dudmuck 0:8f0d0ae0a077 1665 // NON-STICKY
dudmuck 0:8f0d0ae0a077 1666 case MOTE_MAC_DEV_STATUS_ANS:
dudmuck 0:8f0d0ae0a077 1667 { // 2 bytes payload
dudmuck 0:8f0d0ae0a077 1668 i += 2;
dudmuck 0:8f0d0ae0a077 1669 break;
dudmuck 0:8f0d0ae0a077 1670 }
dudmuck 0:8f0d0ae0a077 1671 case MOTE_MAC_LINK_CHECK_REQ:
dudmuck 0:8f0d0ae0a077 1672 { // 0 byte payload
dudmuck 0:8f0d0ae0a077 1673 break;
dudmuck 0:8f0d0ae0a077 1674 }
dudmuck 0:8f0d0ae0a077 1675 default:
dudmuck 0:8f0d0ae0a077 1676 break;
dudmuck 0:8f0d0ae0a077 1677 }
dudmuck 0:8f0d0ae0a077 1678 }
dudmuck 0:8f0d0ae0a077 1679
dudmuck 0:8f0d0ae0a077 1680 return cmdCount;
dudmuck 0:8f0d0ae0a077 1681 }
dudmuck 0:8f0d0ae0a077 1682
dudmuck 0:8f0d0ae0a077 1683 static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr )
dudmuck 0:8f0d0ae0a077 1684 {
dudmuck 0:8f0d0ae0a077 1685 while( macIndex < commandsSize )
dudmuck 0:8f0d0ae0a077 1686 {
dudmuck 0:8f0d0ae0a077 1687 // Decode Frame MAC commands
dudmuck 0:8f0d0ae0a077 1688 switch( payload[macIndex++] )
dudmuck 0:8f0d0ae0a077 1689 {
dudmuck 0:8f0d0ae0a077 1690 case SRV_MAC_LINK_CHECK_ANS:
dudmuck 0:8f0d0ae0a077 1691 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1692 MlmeConfirm.DemodMargin = payload[macIndex++];
dudmuck 0:8f0d0ae0a077 1693 MlmeConfirm.NbGateways = payload[macIndex++];
dudmuck 0:8f0d0ae0a077 1694 break;
dudmuck 0:8f0d0ae0a077 1695 case SRV_MAC_DEV_STATUS_REQ:
dudmuck 0:8f0d0ae0a077 1696 {
dudmuck 0:8f0d0ae0a077 1697 uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
dudmuck 0:8f0d0ae0a077 1698 if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) )
dudmuck 0:8f0d0ae0a077 1699 {
dudmuck 0:8f0d0ae0a077 1700 batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
dudmuck 0:8f0d0ae0a077 1701 }
dudmuck 0:8f0d0ae0a077 1702 AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
dudmuck 0:8f0d0ae0a077 1703 break;
dudmuck 0:8f0d0ae0a077 1704 }
dudmuck 0:8f0d0ae0a077 1705 case SRV_MAC_RX_TIMING_SETUP_REQ:
dudmuck 0:8f0d0ae0a077 1706 {
dudmuck 0:8f0d0ae0a077 1707 uint8_t delay = payload[macIndex++] & 0x0F;
dudmuck 0:8f0d0ae0a077 1708
dudmuck 0:8f0d0ae0a077 1709 if( delay == 0 )
dudmuck 0:8f0d0ae0a077 1710 {
dudmuck 0:8f0d0ae0a077 1711 delay++;
dudmuck 0:8f0d0ae0a077 1712 }
dudmuck 0:8f0d0ae0a077 1713 LoRaMacParams.ReceiveDelay_us = delay * 1e6;
dudmuck 0:8f0d0ae0a077 1714 AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
dudmuck 0:8f0d0ae0a077 1715 }
dudmuck 0:8f0d0ae0a077 1716 break;
dudmuck 0:8f0d0ae0a077 1717 default:
dudmuck 0:8f0d0ae0a077 1718 // Unknown command. ABORT MAC commands processing
dudmuck 0:8f0d0ae0a077 1719 return;
dudmuck 0:8f0d0ae0a077 1720 }
dudmuck 0:8f0d0ae0a077 1721 }
dudmuck 0:8f0d0ae0a077 1722 }
dudmuck 0:8f0d0ae0a077 1723
dudmuck 0:8f0d0ae0a077 1724 LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
dudmuck 0:8f0d0ae0a077 1725 {
dudmuck 0:8f0d0ae0a077 1726 LoRaMacFrameCtrl_t fCtrl;
dudmuck 0:8f0d0ae0a077 1727 LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 1728
dudmuck 0:8f0d0ae0a077 1729 fCtrl.Value = 0;
dudmuck 0:8f0d0ae0a077 1730 fCtrl.Bits.FOptsLen = 0;
dudmuck 0:8f0d0ae0a077 1731 fCtrl.Bits.FPending = 0;
dudmuck 0:8f0d0ae0a077 1732 fCtrl.Bits.Ack = false;
dudmuck 0:8f0d0ae0a077 1733 fCtrl.Bits.AdrAckReq = false;
dudmuck 0:8f0d0ae0a077 1734 fCtrl.Bits.Adr = false;
dudmuck 0:8f0d0ae0a077 1735
dudmuck 0:8f0d0ae0a077 1736 // Prepare the frame
dudmuck 0:8f0d0ae0a077 1737 status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
dudmuck 0:8f0d0ae0a077 1738
dudmuck 0:8f0d0ae0a077 1739 // Validate status
dudmuck 0:8f0d0ae0a077 1740 if( status != LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 1741 {
dudmuck 0:8f0d0ae0a077 1742 return status;
dudmuck 0:8f0d0ae0a077 1743 }
dudmuck 0:8f0d0ae0a077 1744
dudmuck 0:8f0d0ae0a077 1745 // Reset confirm parameters
dudmuck 0:8f0d0ae0a077 1746 McpsConfirm.AckReceived = false;
dudmuck 0:8f0d0ae0a077 1747 McpsConfirm.UpLinkCounter = UpLinkCounter;
dudmuck 0:8f0d0ae0a077 1748
dudmuck 25:fed9d5b77183 1749 ScheduleTx();
dudmuck 25:fed9d5b77183 1750
dudmuck 25:fed9d5b77183 1751 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1752 }
dudmuck 0:8f0d0ae0a077 1753
dudmuck 0:8f0d0ae0a077 1754
dudmuck 0:8f0d0ae0a077 1755 static void ResetMacParameters( void )
dudmuck 0:8f0d0ae0a077 1756 {
Wayne Roberts 29:ad409c68c0a6 1757 LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = false;
dudmuck 0:8f0d0ae0a077 1758
dudmuck 0:8f0d0ae0a077 1759 // Counters
dudmuck 0:8f0d0ae0a077 1760 UpLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1761 DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1762
dudmuck 0:8f0d0ae0a077 1763 ChannelsNbRepCounter = 0;
dudmuck 0:8f0d0ae0a077 1764
dudmuck 0:8f0d0ae0a077 1765 MacCommandsBufferIndex = 0;
dudmuck 0:8f0d0ae0a077 1766 MacCommandsBufferToRepeatIndex = 0;
dudmuck 0:8f0d0ae0a077 1767
dudmuck 0:8f0d0ae0a077 1768 IsRxWindowsEnabled = true;
dudmuck 0:8f0d0ae0a077 1769
dudmuck 0:8f0d0ae0a077 1770 LoRaMacParams.ChannelsTxPower = LoRaMacParamsDefaults.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 1771 LoRaMacParams.ChannelsDatarate_fixed = LoRaMacParamsDefaults.ChannelsDatarate_fixed;
dudmuck 0:8f0d0ae0a077 1772
dudmuck 0:8f0d0ae0a077 1773 LoRaMacParams.Rx1DrOffset = LoRaMacParamsDefaults.Rx1DrOffset;
dudmuck 0:8f0d0ae0a077 1774
Wayne Roberts 29:ad409c68c0a6 1775 LoRaMacFlags.Bits.NodeAckRequested = false;
Wayne Roberts 29:ad409c68c0a6 1776 LoRaMacFlags.Bits.SrvAckRequested = false;
dudmuck 0:8f0d0ae0a077 1777 MacCommandsInNextTx = false;
dudmuck 0:8f0d0ae0a077 1778
dudmuck 0:8f0d0ae0a077 1779 // Reset Multicast downlink counters
dudmuck 0:8f0d0ae0a077 1780 MulticastParams_t *cur = MulticastChannels;
dudmuck 0:8f0d0ae0a077 1781 while( cur != NULL )
dudmuck 0:8f0d0ae0a077 1782 {
dudmuck 0:8f0d0ae0a077 1783 cur->DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1784 cur = cur->Next;
dudmuck 0:8f0d0ae0a077 1785 }
dudmuck 0:8f0d0ae0a077 1786
dudmuck 0:8f0d0ae0a077 1787 }
dudmuck 0:8f0d0ae0a077 1788
dudmuck 0:8f0d0ae0a077 1789 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
dudmuck 0:8f0d0ae0a077 1790 {
dudmuck 0:8f0d0ae0a077 1791 uint16_t i;
dudmuck 0:8f0d0ae0a077 1792 uint32_t mic = 0;
dudmuck 0:8f0d0ae0a077 1793 const void* payload = fBuffer;
dudmuck 0:8f0d0ae0a077 1794 uint8_t framePort = fPort;
Wayne Roberts 29:ad409c68c0a6 1795 uint8_t LoRaMacTxPayloadLen = 0;
Wayne Roberts 29:ad409c68c0a6 1796
Wayne Roberts 29:ad409c68c0a6 1797 LoRaMacFlags.Bits.NodeAckRequested = false;
Wayne Roberts 29:ad409c68c0a6 1798 tx_buf_len = 0;
dudmuck 0:8f0d0ae0a077 1799
dudmuck 0:8f0d0ae0a077 1800 if( fBuffer == NULL )
dudmuck 0:8f0d0ae0a077 1801 {
dudmuck 0:8f0d0ae0a077 1802 fBufferSize = 0;
dudmuck 0:8f0d0ae0a077 1803 }
dudmuck 0:8f0d0ae0a077 1804
dudmuck 0:8f0d0ae0a077 1805 LoRaMacTxPayloadLen = fBufferSize;
dudmuck 0:8f0d0ae0a077 1806
Wayne Roberts 29:ad409c68c0a6 1807 Radio::radio.tx_buf[tx_buf_len++] = macHdr->Value;
dudmuck 0:8f0d0ae0a077 1808
dudmuck 0:8f0d0ae0a077 1809 switch( macHdr->Bits.MType )
dudmuck 0:8f0d0ae0a077 1810 {
dudmuck 0:8f0d0ae0a077 1811 case FRAME_TYPE_JOIN_REQ:
Wayne Roberts 29:ad409c68c0a6 1812 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacAppEui, 8 );
Wayne Roberts 29:ad409c68c0a6 1813 tx_buf_len += 8;
Wayne Roberts 29:ad409c68c0a6 1814 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
Wayne Roberts 29:ad409c68c0a6 1815 tx_buf_len += 8;
Wayne Roberts 29:ad409c68c0a6 1816
Wayne Roberts 29:ad409c68c0a6 1817 LoRaMacDevNonce = Radio::Random( );
Wayne Roberts 29:ad409c68c0a6 1818
Wayne Roberts 29:ad409c68c0a6 1819 Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1820 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1821
Wayne Roberts 29:ad409c68c0a6 1822 LoRaMacJoinComputeMic( Radio::radio.tx_buf, tx_buf_len & 0xFF, LoRaMacAppKey, &mic );
Wayne Roberts 29:ad409c68c0a6 1823
Wayne Roberts 29:ad409c68c0a6 1824 Radio::radio.tx_buf[tx_buf_len++] = mic & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1825 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 8 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1826 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 16 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1827 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 24 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 1828
dudmuck 0:8f0d0ae0a077 1829 break;
dudmuck 0:8f0d0ae0a077 1830 case FRAME_TYPE_DATA_CONFIRMED_UP:
Wayne Roberts 29:ad409c68c0a6 1831 LoRaMacFlags.Bits.NodeAckRequested = true;
dudmuck 0:8f0d0ae0a077 1832 //Intentional fallthrough
dudmuck 0:8f0d0ae0a077 1833 case FRAME_TYPE_DATA_UNCONFIRMED_UP:
Wayne Roberts 29:ad409c68c0a6 1834 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
dudmuck 0:8f0d0ae0a077 1835 {
dudmuck 0:8f0d0ae0a077 1836 return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet
dudmuck 0:8f0d0ae0a077 1837 }
dudmuck 0:8f0d0ae0a077 1838
dudmuck 0:8f0d0ae0a077 1839 fCtrl->Bits.AdrAckReq = 0;
dudmuck 0:8f0d0ae0a077 1840
Wayne Roberts 29:ad409c68c0a6 1841 if( LoRaMacFlags.Bits.SrvAckRequested == true )
dudmuck 0:8f0d0ae0a077 1842 {
Wayne Roberts 29:ad409c68c0a6 1843 LoRaMacFlags.Bits.SrvAckRequested = false;
dudmuck 0:8f0d0ae0a077 1844 fCtrl->Bits.Ack = 1;
dudmuck 0:8f0d0ae0a077 1845 }
dudmuck 0:8f0d0ae0a077 1846
Wayne Roberts 29:ad409c68c0a6 1847 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1848 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1849 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1850 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1851
Wayne Roberts 29:ad409c68c0a6 1852 Radio::radio.tx_buf[tx_buf_len++] = fCtrl->Value;
Wayne Roberts 29:ad409c68c0a6 1853
Wayne Roberts 29:ad409c68c0a6 1854 Radio::radio.tx_buf[tx_buf_len++] = UpLinkCounter & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1855 Radio::radio.tx_buf[tx_buf_len++] = ( UpLinkCounter >> 8 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 1856
dudmuck 0:8f0d0ae0a077 1857 // Copy the MAC commands which must be re-send into the MAC command buffer
dudmuck 0:8f0d0ae0a077 1858 memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex );
dudmuck 0:8f0d0ae0a077 1859 MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex;
dudmuck 0:8f0d0ae0a077 1860
dudmuck 0:8f0d0ae0a077 1861 if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
dudmuck 0:8f0d0ae0a077 1862 {
dudmuck 0:8f0d0ae0a077 1863 if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) )
dudmuck 0:8f0d0ae0a077 1864 {
dudmuck 0:8f0d0ae0a077 1865 fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
dudmuck 0:8f0d0ae0a077 1866
dudmuck 0:8f0d0ae0a077 1867 // Update FCtrl field with new value of OptionsLength
Wayne Roberts 29:ad409c68c0a6 1868 Radio::radio.tx_buf[0x05] = fCtrl->Value;
dudmuck 0:8f0d0ae0a077 1869 for( i = 0; i < MacCommandsBufferIndex; i++ )
dudmuck 0:8f0d0ae0a077 1870 {
Wayne Roberts 29:ad409c68c0a6 1871 Radio::radio.tx_buf[tx_buf_len++] = MacCommandsBuffer[i];
dudmuck 0:8f0d0ae0a077 1872 }
dudmuck 0:8f0d0ae0a077 1873 }
dudmuck 0:8f0d0ae0a077 1874 }
dudmuck 0:8f0d0ae0a077 1875 else
dudmuck 0:8f0d0ae0a077 1876 {
dudmuck 0:8f0d0ae0a077 1877 if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) )
dudmuck 0:8f0d0ae0a077 1878 {
dudmuck 0:8f0d0ae0a077 1879 LoRaMacTxPayloadLen = MacCommandsBufferIndex;
dudmuck 0:8f0d0ae0a077 1880 payload = MacCommandsBuffer;
dudmuck 0:8f0d0ae0a077 1881 framePort = 0;
dudmuck 0:8f0d0ae0a077 1882 }
dudmuck 0:8f0d0ae0a077 1883 }
dudmuck 0:8f0d0ae0a077 1884 MacCommandsInNextTx = false;
dudmuck 0:8f0d0ae0a077 1885 // Store MAC commands which must be re-send in case the device does not receive a downlink anymore
dudmuck 0:8f0d0ae0a077 1886 MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat( MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat );
dudmuck 0:8f0d0ae0a077 1887 if( MacCommandsBufferToRepeatIndex > 0 )
dudmuck 0:8f0d0ae0a077 1888 {
dudmuck 0:8f0d0ae0a077 1889 MacCommandsInNextTx = true;
dudmuck 0:8f0d0ae0a077 1890 }
dudmuck 0:8f0d0ae0a077 1891
dudmuck 0:8f0d0ae0a077 1892 if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
dudmuck 0:8f0d0ae0a077 1893 {
Wayne Roberts 29:ad409c68c0a6 1894 Radio::radio.tx_buf[tx_buf_len++] = framePort;
dudmuck 0:8f0d0ae0a077 1895
dudmuck 0:8f0d0ae0a077 1896 if( framePort == 0 )
dudmuck 0:8f0d0ae0a077 1897 {
Wayne Roberts 29:ad409c68c0a6 1898 LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &Radio::radio.tx_buf[tx_buf_len] );
dudmuck 0:8f0d0ae0a077 1899 }
dudmuck 0:8f0d0ae0a077 1900 else
dudmuck 0:8f0d0ae0a077 1901 {
Wayne Roberts 29:ad409c68c0a6 1902 LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &Radio::radio.tx_buf[tx_buf_len] );
dudmuck 0:8f0d0ae0a077 1903 }
dudmuck 0:8f0d0ae0a077 1904 }
Wayne Roberts 29:ad409c68c0a6 1905 tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
Wayne Roberts 29:ad409c68c0a6 1906
Wayne Roberts 29:ad409c68c0a6 1907 LoRaMacComputeMic( Radio::radio.tx_buf, tx_buf_len, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic );
Wayne Roberts 29:ad409c68c0a6 1908
Wayne Roberts 29:ad409c68c0a6 1909 Radio::radio.tx_buf[tx_buf_len + 0] = mic & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1910 Radio::radio.tx_buf[tx_buf_len + 1] = ( mic >> 8 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1911 Radio::radio.tx_buf[tx_buf_len + 2] = ( mic >> 16 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1912 Radio::radio.tx_buf[tx_buf_len + 3] = ( mic >> 24 ) & 0xFF;
Wayne Roberts 29:ad409c68c0a6 1913
Wayne Roberts 29:ad409c68c0a6 1914 tx_buf_len += LORAMAC_MFR_LEN;
dudmuck 0:8f0d0ae0a077 1915
dudmuck 0:8f0d0ae0a077 1916 break;
dudmuck 0:8f0d0ae0a077 1917 case FRAME_TYPE_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 1918 if( ( fBuffer != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
dudmuck 0:8f0d0ae0a077 1919 {
Wayne Roberts 29:ad409c68c0a6 1920 memcpy1( Radio::radio.tx_buf + tx_buf_len, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen );
Wayne Roberts 29:ad409c68c0a6 1921 tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
dudmuck 0:8f0d0ae0a077 1922 }
dudmuck 0:8f0d0ae0a077 1923 break;
dudmuck 0:8f0d0ae0a077 1924 default:
dudmuck 0:8f0d0ae0a077 1925 return LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 1926 }
dudmuck 0:8f0d0ae0a077 1927
dudmuck 0:8f0d0ae0a077 1928 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1929 }
dudmuck 0:8f0d0ae0a077 1930
dudmuck 0:8f0d0ae0a077 1931
dudmuck 0:8f0d0ae0a077 1932 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout )
dudmuck 0:8f0d0ae0a077 1933 {
dudmuck 0:8f0d0ae0a077 1934 int8_t txPowerIndex = 0;
dudmuck 0:8f0d0ae0a077 1935 int8_t txPower = 0;
dudmuck 0:8f0d0ae0a077 1936
dudmuck 0:8f0d0ae0a077 1937 txPowerIndex = LoRaMacParams.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 1938 txPower = TxPowers[txPowerIndex];
Wayne Roberts 29:ad409c68c0a6 1939 Radio::SetTxContinuousWave( Channels[Channel].Frequency, txPower, 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 LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power )
dudmuck 0:8f0d0ae0a077 1945 {
Wayne Roberts 29:ad409c68c0a6 1946 Radio::SetTxContinuousWave( frequency, power, timeout );
dudmuck 0:8f0d0ae0a077 1947
dudmuck 0:8f0d0ae0a077 1948 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 1949 }
dudmuck 0:8f0d0ae0a077 1950
dudmuck 0:8f0d0ae0a077 1951 void seconds()
dudmuck 0:8f0d0ae0a077 1952 {
Wayne Roberts 29:ad409c68c0a6 1953 mac_printf("second\r\n");
Wayne Roberts 29:ad409c68c0a6 1954 }
Wayne Roberts 29:ad409c68c0a6 1955
Wayne Roberts 29:ad409c68c0a6 1956 void on_dio0_top_half(us_timestamp_t dio0_at)
Wayne Roberts 29:ad409c68c0a6 1957 {
Wayne Roberts 29:ad409c68c0a6 1958 mac_printf("dio0th\r\n");
dudmuck 0:8f0d0ae0a077 1959 }
dudmuck 0:8f0d0ae0a077 1960
Wayne Roberts 29:ad409c68c0a6 1961 unsigned get_symbol_period_us(uint8_t sf)
Wayne Roberts 29:ad409c68c0a6 1962 {
Wayne Roberts 29:ad409c68c0a6 1963 float bwMHz = LORA_BANDWIDTH_KHZ / 1000.0;
Wayne Roberts 29:ad409c68c0a6 1964 // return symbol period in microseconds
Wayne Roberts 29:ad409c68c0a6 1965 return (1 << sf) / bwMHz;
Wayne Roberts 29:ad409c68c0a6 1966 }
Wayne Roberts 29:ad409c68c0a6 1967
Wayne Roberts 29:ad409c68c0a6 1968 const RadioEvents_t rev = {
Wayne Roberts 29:ad409c68c0a6 1969 /* Dio0_top_half */ on_dio0_top_half,
Wayne Roberts 33:bc0b6be19e07 1970 /* TxDone_topHalf */ OnRadioTxDone_topHalf,
Wayne Roberts 29:ad409c68c0a6 1971 /* TxDone_botHalf */ OnRadioTxDone_bh,
Wayne Roberts 29:ad409c68c0a6 1972 /* TxTimeout */ OnRadioTxTimeout,
Wayne Roberts 29:ad409c68c0a6 1973 /* RxDone */ OnRadioRxDone,
Wayne Roberts 29:ad409c68c0a6 1974 /* RxTimeout */ OnRadioRxTimeout,
Wayne Roberts 29:ad409c68c0a6 1975 /* RxError */ OnRadioRxError,
Wayne Roberts 29:ad409c68c0a6 1976 /* FhssChangeChannel */NULL,
Wayne Roberts 29:ad409c68c0a6 1977 /* CadDone */ NULL
Wayne Roberts 29:ad409c68c0a6 1978 };
Wayne Roberts 29:ad409c68c0a6 1979
dudmuck 0:8f0d0ae0a077 1980 LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks )
dudmuck 0:8f0d0ae0a077 1981 {
dudmuck 0:8f0d0ae0a077 1982 if( primitives == 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 if( ( primitives->MacMcpsConfirm == NULL ) ||
dudmuck 0:8f0d0ae0a077 1988 ( primitives->MacMcpsIndication == NULL ) ||
dudmuck 0:8f0d0ae0a077 1989 ( primitives->MacMlmeConfirm == NULL ) )
dudmuck 0:8f0d0ae0a077 1990 {
dudmuck 0:8f0d0ae0a077 1991 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 1992 }
dudmuck 0:8f0d0ae0a077 1993
dudmuck 0:8f0d0ae0a077 1994 LoRaMacPrimitives = primitives;
dudmuck 0:8f0d0ae0a077 1995 LoRaMacCallbacks = callbacks;
dudmuck 0:8f0d0ae0a077 1996
dudmuck 0:8f0d0ae0a077 1997 LoRaMacFlags.Value = 0;
dudmuck 0:8f0d0ae0a077 1998
dudmuck 0:8f0d0ae0a077 1999 JoinRequestTrials = 0;
dudmuck 0:8f0d0ae0a077 2000 MaxJoinRequestTrials = 255;
dudmuck 0:8f0d0ae0a077 2001
Wayne Roberts 29:ad409c68c0a6 2002 BeaconCtx.symbol_period_us = get_symbol_period_us(Datarates[LORAMAC_DEFAULT_DATARATE]);
dudmuck 0:8f0d0ae0a077 2003
dudmuck 0:8f0d0ae0a077 2004 // Reset to defaults
dudmuck 0:8f0d0ae0a077 2005 LoRaMacParamsDefaults.ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
dudmuck 0:8f0d0ae0a077 2006 LoRaMacParamsDefaults.ChannelsDatarate_fixed = LORAMAC_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 2007
Wayne Roberts 29:ad409c68c0a6 2008 LoRaMacParamsDefaults.SystemMaxRxError_ms = 20;
Wayne Roberts 29:ad409c68c0a6 2009 LoRaMacParamsDefaults.MinRxSymbols = (LoRaMacParamsDefaults.SystemMaxRxError_ms * 1000) / BeaconCtx.symbol_period_us;
Wayne Roberts 29:ad409c68c0a6 2010 if (LoRaMacParamsDefaults.MinRxSymbols < MIN_SYMBOL_TIMEOUT)
Wayne Roberts 29:ad409c68c0a6 2011 LoRaMacParamsDefaults.MinRxSymbols = MIN_SYMBOL_TIMEOUT;
Wayne Roberts 29:ad409c68c0a6 2012
dudmuck 0:8f0d0ae0a077 2013 LoRaMacParamsDefaults.MaxRxWindow = MAX_RX_WINDOW;
dudmuck 0:8f0d0ae0a077 2014
dudmuck 0:8f0d0ae0a077 2015 LoRaMacParamsDefaults.ReceiveDelay_us = RECEIVE_DELAY_us;
dudmuck 0:8f0d0ae0a077 2016 LoRaMacParamsDefaults.JoinAcceptDelay_us = JOIN_ACCEPT_DELAY_us;
dudmuck 0:8f0d0ae0a077 2017
dudmuck 0:8f0d0ae0a077 2018 LoRaMacParamsDefaults.ChannelsNbRep = 1;
dudmuck 0:8f0d0ae0a077 2019 LoRaMacParamsDefaults.Rx1DrOffset = 0;
dudmuck 0:8f0d0ae0a077 2020
dudmuck 0:8f0d0ae0a077 2021 for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
dudmuck 0:8f0d0ae0a077 2022 {
dudmuck 0:8f0d0ae0a077 2023 Channels[i].Frequency = LORAMAC_FIRST_CHANNEL + (i * LORAMAC_STEPWIDTH_CHANNEL);
dudmuck 18:9ac71c0eb70d 2024 Channels[i].DrRange.Value = (LORAMAC_MAX_DATARATE << 4) | LORAMAC_MIN_DATARATE;
dudmuck 0:8f0d0ae0a077 2025 Channels[i].Band = 0;
dudmuck 0:8f0d0ae0a077 2026 }
dudmuck 0:8f0d0ae0a077 2027
dudmuck 0:8f0d0ae0a077 2028 // Init parameters which are not set in function ResetMacParameters
Wayne Roberts 29:ad409c68c0a6 2029 LoRaMacParams.SystemMaxRxError_ms = LoRaMacParamsDefaults.SystemMaxRxError_ms;
dudmuck 0:8f0d0ae0a077 2030 LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols;
dudmuck 0:8f0d0ae0a077 2031 LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow;
dudmuck 0:8f0d0ae0a077 2032 LoRaMacParams.ReceiveDelay_us = LoRaMacParamsDefaults.ReceiveDelay_us;
dudmuck 0:8f0d0ae0a077 2033 LoRaMacParams.JoinAcceptDelay_us = LoRaMacParamsDefaults.JoinAcceptDelay_us;
dudmuck 0:8f0d0ae0a077 2034 LoRaMacParams.ChannelsNbRep = LoRaMacParamsDefaults.ChannelsNbRep;
dudmuck 0:8f0d0ae0a077 2035
dudmuck 0:8f0d0ae0a077 2036 ResetMacParameters( );
dudmuck 0:8f0d0ae0a077 2037
dudmuck 0:8f0d0ae0a077 2038 // Initialize Radio driver
Wayne Roberts 29:ad409c68c0a6 2039 Radio::Init(&rev);
Wayne Roberts 29:ad409c68c0a6 2040 // lpt started later. lpt will have smaller number.
Wayne Roberts 29:ad409c68c0a6 2041 lpt_offset = _rx_timeout.read_us() - Radio::lpt.read_us();
Wayne Roberts 29:ad409c68c0a6 2042 mac_printf("lpt_offset:%d\r\n", lpt_offset);
dudmuck 0:8f0d0ae0a077 2043
dudmuck 0:8f0d0ae0a077 2044 // Random seed initialization
Wayne Roberts 29:ad409c68c0a6 2045 srand1( Radio::Random( ) );
dudmuck 0:8f0d0ae0a077 2046
dudmuck 0:8f0d0ae0a077 2047 PublicNetwork = true;
Wayne Roberts 29:ad409c68c0a6 2048 Radio::SetPublicNetwork( PublicNetwork );
Wayne Roberts 29:ad409c68c0a6 2049 Radio::Sleep( );
Wayne Roberts 29:ad409c68c0a6 2050
Wayne Roberts 29:ad409c68c0a6 2051 RxWindowsParam = ComputeRxWindowParameters(LORAMAC_DEFAULT_DATARATE, LoRaMacParams.SystemMaxRxError_ms);
dudmuck 0:8f0d0ae0a077 2052
dudmuck 0:8f0d0ae0a077 2053 return LORAMAC_STATUS_OK;
Wayne Roberts 29:ad409c68c0a6 2054 } // ..LoRaMacInitialization()
dudmuck 0:8f0d0ae0a077 2055
dudmuck 0:8f0d0ae0a077 2056 LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
dudmuck 0:8f0d0ae0a077 2057 {
dudmuck 0:8f0d0ae0a077 2058 uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
dudmuck 0:8f0d0ae0a077 2059
dudmuck 0:8f0d0ae0a077 2060 if( txInfo == NULL )
dudmuck 0:8f0d0ae0a077 2061 {
dudmuck 0:8f0d0ae0a077 2062 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2063 }
dudmuck 0:8f0d0ae0a077 2064
Wayne Roberts 29:ad409c68c0a6 2065 txInfo->CurrentPayloadSize = LORAMAC_PHY_MAXPAYLOAD;
dudmuck 0:8f0d0ae0a077 2066
dudmuck 0:8f0d0ae0a077 2067 if( txInfo->CurrentPayloadSize >= fOptLen )
dudmuck 0:8f0d0ae0a077 2068 {
dudmuck 0:8f0d0ae0a077 2069 txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen;
dudmuck 0:8f0d0ae0a077 2070 }
dudmuck 0:8f0d0ae0a077 2071 else
dudmuck 0:8f0d0ae0a077 2072 {
dudmuck 0:8f0d0ae0a077 2073 return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
dudmuck 0:8f0d0ae0a077 2074 }
dudmuck 0:8f0d0ae0a077 2075
dudmuck 0:8f0d0ae0a077 2076 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2077 }
dudmuck 0:8f0d0ae0a077 2078
dudmuck 0:8f0d0ae0a077 2079 LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
dudmuck 0:8f0d0ae0a077 2080 {
dudmuck 0:8f0d0ae0a077 2081 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2082
dudmuck 0:8f0d0ae0a077 2083 if( mibGet == NULL )
dudmuck 0:8f0d0ae0a077 2084 {
dudmuck 0:8f0d0ae0a077 2085 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2086 }
dudmuck 0:8f0d0ae0a077 2087
dudmuck 0:8f0d0ae0a077 2088 switch( mibGet->Type )
dudmuck 0:8f0d0ae0a077 2089 {
dudmuck 0:8f0d0ae0a077 2090 case MIB_NETWORK_JOINED:
dudmuck 0:8f0d0ae0a077 2091 {
Wayne Roberts 29:ad409c68c0a6 2092 mibGet->Param.IsNetworkJoined = LoRaMacFlags.Bits.IsLoRaMacNetworkJoined;
dudmuck 0:8f0d0ae0a077 2093 break;
dudmuck 0:8f0d0ae0a077 2094 }
dudmuck 0:8f0d0ae0a077 2095 case MIB_NET_ID:
dudmuck 0:8f0d0ae0a077 2096 {
dudmuck 0:8f0d0ae0a077 2097 mibGet->Param.NetID = LoRaMacNetID;
dudmuck 0:8f0d0ae0a077 2098 break;
dudmuck 0:8f0d0ae0a077 2099 }
dudmuck 0:8f0d0ae0a077 2100 case MIB_DEV_ADDR:
dudmuck 0:8f0d0ae0a077 2101 {
dudmuck 0:8f0d0ae0a077 2102 mibGet->Param.DevAddr = LoRaMacDevAddr;
dudmuck 0:8f0d0ae0a077 2103 break;
dudmuck 0:8f0d0ae0a077 2104 }
dudmuck 0:8f0d0ae0a077 2105 case MIB_NWK_SKEY:
dudmuck 0:8f0d0ae0a077 2106 {
dudmuck 0:8f0d0ae0a077 2107 mibGet->Param.NwkSKey = LoRaMacNwkSKey;
dudmuck 0:8f0d0ae0a077 2108 break;
dudmuck 0:8f0d0ae0a077 2109 }
dudmuck 0:8f0d0ae0a077 2110 case MIB_APP_SKEY:
dudmuck 0:8f0d0ae0a077 2111 {
dudmuck 0:8f0d0ae0a077 2112 mibGet->Param.AppSKey = LoRaMacAppSKey;
dudmuck 0:8f0d0ae0a077 2113 break;
dudmuck 0:8f0d0ae0a077 2114 }
dudmuck 0:8f0d0ae0a077 2115 case MIB_PUBLIC_NETWORK:
dudmuck 0:8f0d0ae0a077 2116 {
dudmuck 0:8f0d0ae0a077 2117 mibGet->Param.EnablePublicNetwork = PublicNetwork;
dudmuck 0:8f0d0ae0a077 2118 break;
dudmuck 0:8f0d0ae0a077 2119 }
dudmuck 0:8f0d0ae0a077 2120 case MIB_CHANNELS_NB_REP:
dudmuck 0:8f0d0ae0a077 2121 {
dudmuck 0:8f0d0ae0a077 2122 mibGet->Param.ChannelNbRep = LoRaMacParams.ChannelsNbRep;
dudmuck 0:8f0d0ae0a077 2123 break;
dudmuck 0:8f0d0ae0a077 2124 }
dudmuck 0:8f0d0ae0a077 2125 case MIB_MAX_RX_WINDOW_DURATION:
dudmuck 0:8f0d0ae0a077 2126 {
dudmuck 0:8f0d0ae0a077 2127 mibGet->Param.MaxRxWindow = LoRaMacParams.MaxRxWindow;
dudmuck 0:8f0d0ae0a077 2128 break;
dudmuck 0:8f0d0ae0a077 2129 }
dudmuck 0:8f0d0ae0a077 2130 case MIB_CHANNELS_DEFAULT_TX_POWER:
dudmuck 0:8f0d0ae0a077 2131 {
dudmuck 0:8f0d0ae0a077 2132 mibGet->Param.ChannelsDefaultTxPower = LoRaMacParamsDefaults.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 2133 break;
dudmuck 0:8f0d0ae0a077 2134 }
dudmuck 0:8f0d0ae0a077 2135 case MIB_CHANNELS_TX_POWER:
dudmuck 0:8f0d0ae0a077 2136 {
dudmuck 0:8f0d0ae0a077 2137 mibGet->Param.ChannelsTxPower = LoRaMacParams.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 2138 break;
dudmuck 0:8f0d0ae0a077 2139 }
dudmuck 0:8f0d0ae0a077 2140 case MIB_UPLINK_COUNTER:
dudmuck 0:8f0d0ae0a077 2141 {
dudmuck 0:8f0d0ae0a077 2142 mibGet->Param.UpLinkCounter = UpLinkCounter;
dudmuck 0:8f0d0ae0a077 2143 break;
dudmuck 0:8f0d0ae0a077 2144 }
dudmuck 0:8f0d0ae0a077 2145 case MIB_DOWNLINK_COUNTER:
dudmuck 0:8f0d0ae0a077 2146 {
dudmuck 0:8f0d0ae0a077 2147 mibGet->Param.DownLinkCounter = DownLinkCounter;
dudmuck 0:8f0d0ae0a077 2148 break;
dudmuck 0:8f0d0ae0a077 2149 }
dudmuck 0:8f0d0ae0a077 2150 case MIB_MULTICAST_CHANNEL:
dudmuck 0:8f0d0ae0a077 2151 {
dudmuck 0:8f0d0ae0a077 2152 mibGet->Param.MulticastList = MulticastChannels;
dudmuck 0:8f0d0ae0a077 2153 break;
dudmuck 0:8f0d0ae0a077 2154 }
dudmuck 0:8f0d0ae0a077 2155 case MIB_SYSTEM_MAX_RX_ERROR:
dudmuck 0:8f0d0ae0a077 2156 {
Wayne Roberts 29:ad409c68c0a6 2157 mibGet->Param.SystemMaxRxError_ms = LoRaMacParams.SystemMaxRxError_ms;
dudmuck 0:8f0d0ae0a077 2158 break;
dudmuck 0:8f0d0ae0a077 2159 }
dudmuck 0:8f0d0ae0a077 2160 case MIB_MIN_RX_SYMBOLS:
dudmuck 0:8f0d0ae0a077 2161 {
dudmuck 0:8f0d0ae0a077 2162 mibGet->Param.MinRxSymbols = LoRaMacParams.MinRxSymbols;
dudmuck 0:8f0d0ae0a077 2163 break;
dudmuck 0:8f0d0ae0a077 2164 }
dudmuck 0:8f0d0ae0a077 2165 default:
dudmuck 0:8f0d0ae0a077 2166 status = LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 2167 break;
dudmuck 0:8f0d0ae0a077 2168 }
dudmuck 0:8f0d0ae0a077 2169
dudmuck 0:8f0d0ae0a077 2170 return status;
dudmuck 0:8f0d0ae0a077 2171 }
dudmuck 0:8f0d0ae0a077 2172
dudmuck 0:8f0d0ae0a077 2173 LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
dudmuck 0:8f0d0ae0a077 2174 {
dudmuck 0:8f0d0ae0a077 2175 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2176
dudmuck 0:8f0d0ae0a077 2177 if( mibSet == NULL )
dudmuck 0:8f0d0ae0a077 2178 {
dudmuck 0:8f0d0ae0a077 2179 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2180 }
dudmuck 0:8f0d0ae0a077 2181
dudmuck 0:8f0d0ae0a077 2182 switch( mibSet->Type )
dudmuck 0:8f0d0ae0a077 2183 {
dudmuck 0:8f0d0ae0a077 2184 case MIB_NETWORK_JOINED:
dudmuck 0:8f0d0ae0a077 2185 {
Wayne Roberts 29:ad409c68c0a6 2186 LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined;
Wayne Roberts 29:ad409c68c0a6 2187 if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) {
Wayne Roberts 29:ad409c68c0a6 2188 mac_printf("beaconDetach\r\n");
Wayne Roberts 29:ad409c68c0a6 2189 BeaconCtx._timeout_rx.detach();
Wayne Roberts 29:ad409c68c0a6 2190 BeaconCtx._timeout_guard.detach();
dudmuck 16:915815632c1f 2191 BeaconCtx.state = BEACON_STATE_NONE;
dudmuck 16:915815632c1f 2192 }
dudmuck 0:8f0d0ae0a077 2193 break;
dudmuck 0:8f0d0ae0a077 2194 }
dudmuck 0:8f0d0ae0a077 2195 case MIB_NET_ID:
dudmuck 0:8f0d0ae0a077 2196 {
dudmuck 0:8f0d0ae0a077 2197 LoRaMacNetID = mibSet->Param.NetID;
dudmuck 0:8f0d0ae0a077 2198 break;
dudmuck 0:8f0d0ae0a077 2199 }
dudmuck 0:8f0d0ae0a077 2200 case MIB_DEV_ADDR:
dudmuck 0:8f0d0ae0a077 2201 {
dudmuck 0:8f0d0ae0a077 2202 LoRaMacDevAddr = mibSet->Param.DevAddr;
dudmuck 0:8f0d0ae0a077 2203 break;
dudmuck 0:8f0d0ae0a077 2204 }
dudmuck 0:8f0d0ae0a077 2205 case MIB_NWK_SKEY:
dudmuck 0:8f0d0ae0a077 2206 {
dudmuck 0:8f0d0ae0a077 2207 if( mibSet->Param.NwkSKey != NULL )
dudmuck 0:8f0d0ae0a077 2208 {
dudmuck 0:8f0d0ae0a077 2209 memcpy1( LoRaMacNwkSKey, mibSet->Param.NwkSKey,
dudmuck 0:8f0d0ae0a077 2210 sizeof( LoRaMacNwkSKey ) );
dudmuck 0:8f0d0ae0a077 2211 }
dudmuck 0:8f0d0ae0a077 2212 else
dudmuck 0:8f0d0ae0a077 2213 {
dudmuck 0:8f0d0ae0a077 2214 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2215 }
dudmuck 0:8f0d0ae0a077 2216 break;
dudmuck 0:8f0d0ae0a077 2217 }
dudmuck 0:8f0d0ae0a077 2218 case MIB_APP_SKEY:
dudmuck 0:8f0d0ae0a077 2219 {
dudmuck 0:8f0d0ae0a077 2220 if( mibSet->Param.AppSKey != NULL )
dudmuck 0:8f0d0ae0a077 2221 {
dudmuck 0:8f0d0ae0a077 2222 memcpy1( LoRaMacAppSKey, mibSet->Param.AppSKey,
dudmuck 0:8f0d0ae0a077 2223 sizeof( LoRaMacAppSKey ) );
dudmuck 0:8f0d0ae0a077 2224 }
dudmuck 0:8f0d0ae0a077 2225 else
dudmuck 0:8f0d0ae0a077 2226 {
dudmuck 0:8f0d0ae0a077 2227 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2228 }
dudmuck 0:8f0d0ae0a077 2229 break;
dudmuck 0:8f0d0ae0a077 2230 }
dudmuck 0:8f0d0ae0a077 2231 case MIB_PUBLIC_NETWORK:
dudmuck 0:8f0d0ae0a077 2232 {
dudmuck 0:8f0d0ae0a077 2233 PublicNetwork = mibSet->Param.EnablePublicNetwork;
Wayne Roberts 29:ad409c68c0a6 2234 Radio::SetPublicNetwork( PublicNetwork );
dudmuck 0:8f0d0ae0a077 2235 break;
dudmuck 0:8f0d0ae0a077 2236 }
dudmuck 0:8f0d0ae0a077 2237 case MIB_CHANNELS_NB_REP:
dudmuck 0:8f0d0ae0a077 2238 {
dudmuck 0:8f0d0ae0a077 2239 if( ( mibSet->Param.ChannelNbRep >= 1 ) &&
dudmuck 0:8f0d0ae0a077 2240 ( mibSet->Param.ChannelNbRep <= 15 ) )
dudmuck 0:8f0d0ae0a077 2241 {
dudmuck 0:8f0d0ae0a077 2242 LoRaMacParams.ChannelsNbRep = mibSet->Param.ChannelNbRep;
dudmuck 0:8f0d0ae0a077 2243 }
dudmuck 0:8f0d0ae0a077 2244 else
dudmuck 0:8f0d0ae0a077 2245 {
dudmuck 0:8f0d0ae0a077 2246 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2247 }
dudmuck 0:8f0d0ae0a077 2248 break;
dudmuck 0:8f0d0ae0a077 2249 }
dudmuck 0:8f0d0ae0a077 2250 case MIB_MAX_RX_WINDOW_DURATION:
dudmuck 0:8f0d0ae0a077 2251 {
dudmuck 0:8f0d0ae0a077 2252 LoRaMacParams.MaxRxWindow = mibSet->Param.MaxRxWindow;
dudmuck 0:8f0d0ae0a077 2253 break;
dudmuck 0:8f0d0ae0a077 2254 }
dudmuck 0:8f0d0ae0a077 2255 case MIB_CHANNELS_DEFAULT_TX_POWER:
dudmuck 0:8f0d0ae0a077 2256 {
dudmuck 0:8f0d0ae0a077 2257 if( ValueInRange( mibSet->Param.ChannelsDefaultTxPower,
dudmuck 0:8f0d0ae0a077 2258 LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
dudmuck 0:8f0d0ae0a077 2259 {
dudmuck 0:8f0d0ae0a077 2260 LoRaMacParamsDefaults.ChannelsTxPower = mibSet->Param.ChannelsDefaultTxPower;
dudmuck 0:8f0d0ae0a077 2261 }
dudmuck 0:8f0d0ae0a077 2262 else
dudmuck 0:8f0d0ae0a077 2263 {
dudmuck 0:8f0d0ae0a077 2264 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2265 }
dudmuck 0:8f0d0ae0a077 2266 break;
dudmuck 0:8f0d0ae0a077 2267 }
dudmuck 0:8f0d0ae0a077 2268 case MIB_CHANNELS_TX_POWER:
dudmuck 0:8f0d0ae0a077 2269 {
dudmuck 0:8f0d0ae0a077 2270 if( ValueInRange( mibSet->Param.ChannelsTxPower,
dudmuck 0:8f0d0ae0a077 2271 LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
dudmuck 0:8f0d0ae0a077 2272 {
dudmuck 0:8f0d0ae0a077 2273 LoRaMacParams.ChannelsTxPower = mibSet->Param.ChannelsTxPower;
dudmuck 0:8f0d0ae0a077 2274 }
dudmuck 0:8f0d0ae0a077 2275 else
dudmuck 0:8f0d0ae0a077 2276 {
dudmuck 0:8f0d0ae0a077 2277 status = LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2278 }
dudmuck 0:8f0d0ae0a077 2279 break;
dudmuck 0:8f0d0ae0a077 2280 }
dudmuck 0:8f0d0ae0a077 2281 case MIB_UPLINK_COUNTER:
dudmuck 0:8f0d0ae0a077 2282 {
dudmuck 0:8f0d0ae0a077 2283 UpLinkCounter = mibSet->Param.UpLinkCounter;
dudmuck 0:8f0d0ae0a077 2284 break;
dudmuck 0:8f0d0ae0a077 2285 }
dudmuck 0:8f0d0ae0a077 2286 case MIB_DOWNLINK_COUNTER:
dudmuck 0:8f0d0ae0a077 2287 {
dudmuck 0:8f0d0ae0a077 2288 DownLinkCounter = mibSet->Param.DownLinkCounter;
dudmuck 0:8f0d0ae0a077 2289 break;
dudmuck 0:8f0d0ae0a077 2290 }
dudmuck 0:8f0d0ae0a077 2291 case MIB_SYSTEM_MAX_RX_ERROR:
dudmuck 0:8f0d0ae0a077 2292 {
Wayne Roberts 29:ad409c68c0a6 2293 LoRaMacParams.SystemMaxRxError_ms = LoRaMacParamsDefaults.SystemMaxRxError_ms = mibSet->Param.SystemMaxRxError_ms;
dudmuck 0:8f0d0ae0a077 2294 break;
dudmuck 0:8f0d0ae0a077 2295 }
dudmuck 0:8f0d0ae0a077 2296 case MIB_MIN_RX_SYMBOLS:
dudmuck 0:8f0d0ae0a077 2297 {
dudmuck 0:8f0d0ae0a077 2298 LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols = mibSet->Param.MinRxSymbols;
dudmuck 0:8f0d0ae0a077 2299 break;
dudmuck 0:8f0d0ae0a077 2300 }
dudmuck 0:8f0d0ae0a077 2301 default:
dudmuck 0:8f0d0ae0a077 2302 status = LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 2303 break;
dudmuck 0:8f0d0ae0a077 2304 }
dudmuck 0:8f0d0ae0a077 2305
dudmuck 0:8f0d0ae0a077 2306 return status;
dudmuck 0:8f0d0ae0a077 2307 }
dudmuck 0:8f0d0ae0a077 2308
dudmuck 0:8f0d0ae0a077 2309 LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam )
dudmuck 0:8f0d0ae0a077 2310 {
dudmuck 0:8f0d0ae0a077 2311 if( channelParam == NULL )
dudmuck 0:8f0d0ae0a077 2312 {
dudmuck 0:8f0d0ae0a077 2313 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2314 }
dudmuck 0:8f0d0ae0a077 2315
dudmuck 0:8f0d0ae0a077 2316 // Reset downlink counter
dudmuck 0:8f0d0ae0a077 2317 channelParam->DownLinkCounter = 0;
dudmuck 0:8f0d0ae0a077 2318
dudmuck 0:8f0d0ae0a077 2319 if( MulticastChannels == NULL )
dudmuck 0:8f0d0ae0a077 2320 {
dudmuck 0:8f0d0ae0a077 2321 // New node is the fist element
dudmuck 0:8f0d0ae0a077 2322 MulticastChannels = channelParam;
dudmuck 0:8f0d0ae0a077 2323 }
dudmuck 0:8f0d0ae0a077 2324 else
dudmuck 0:8f0d0ae0a077 2325 {
dudmuck 0:8f0d0ae0a077 2326 MulticastParams_t *cur = MulticastChannels;
dudmuck 0:8f0d0ae0a077 2327
dudmuck 0:8f0d0ae0a077 2328 // Search the last node in the list
dudmuck 0:8f0d0ae0a077 2329 while( cur->Next != NULL )
dudmuck 0:8f0d0ae0a077 2330 {
dudmuck 0:8f0d0ae0a077 2331 cur = cur->Next;
dudmuck 0:8f0d0ae0a077 2332 }
dudmuck 0:8f0d0ae0a077 2333 // This function always finds the last node
dudmuck 0:8f0d0ae0a077 2334 cur->Next = channelParam;
dudmuck 0:8f0d0ae0a077 2335 }
dudmuck 0:8f0d0ae0a077 2336
dudmuck 0:8f0d0ae0a077 2337 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2338 }
dudmuck 0:8f0d0ae0a077 2339
dudmuck 0:8f0d0ae0a077 2340 LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam )
dudmuck 0:8f0d0ae0a077 2341 {
dudmuck 0:8f0d0ae0a077 2342 if( channelParam == NULL )
dudmuck 0:8f0d0ae0a077 2343 {
dudmuck 0:8f0d0ae0a077 2344 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2345 }
dudmuck 0:8f0d0ae0a077 2346
dudmuck 0:8f0d0ae0a077 2347 if( MulticastChannels != NULL )
dudmuck 0:8f0d0ae0a077 2348 {
dudmuck 0:8f0d0ae0a077 2349 if( MulticastChannels == channelParam )
dudmuck 0:8f0d0ae0a077 2350 {
dudmuck 0:8f0d0ae0a077 2351 // First element
dudmuck 0:8f0d0ae0a077 2352 MulticastChannels = channelParam->Next;
dudmuck 0:8f0d0ae0a077 2353 }
dudmuck 0:8f0d0ae0a077 2354 else
dudmuck 0:8f0d0ae0a077 2355 {
dudmuck 0:8f0d0ae0a077 2356 MulticastParams_t *cur = MulticastChannels;
dudmuck 0:8f0d0ae0a077 2357
dudmuck 0:8f0d0ae0a077 2358 // Search the node in the list
dudmuck 0:8f0d0ae0a077 2359 while( cur->Next && cur->Next != channelParam )
dudmuck 0:8f0d0ae0a077 2360 {
dudmuck 0:8f0d0ae0a077 2361 cur = cur->Next;
dudmuck 0:8f0d0ae0a077 2362 }
dudmuck 0:8f0d0ae0a077 2363 // If we found the node, remove it
dudmuck 0:8f0d0ae0a077 2364 if( cur->Next )
dudmuck 0:8f0d0ae0a077 2365 {
dudmuck 0:8f0d0ae0a077 2366 cur->Next = channelParam->Next;
dudmuck 0:8f0d0ae0a077 2367 }
dudmuck 0:8f0d0ae0a077 2368 }
dudmuck 0:8f0d0ae0a077 2369 channelParam->Next = NULL;
dudmuck 0:8f0d0ae0a077 2370 }
dudmuck 0:8f0d0ae0a077 2371
dudmuck 0:8f0d0ae0a077 2372 return LORAMAC_STATUS_OK;
dudmuck 0:8f0d0ae0a077 2373 }
dudmuck 0:8f0d0ae0a077 2374
dudmuck 0:8f0d0ae0a077 2375 LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest )
dudmuck 0:8f0d0ae0a077 2376 {
dudmuck 0:8f0d0ae0a077 2377 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 2378 LoRaMacHeader_t macHdr;
dudmuck 0:8f0d0ae0a077 2379
dudmuck 0:8f0d0ae0a077 2380 if( mlmeRequest == NULL )
dudmuck 0:8f0d0ae0a077 2381 {
dudmuck 0:8f0d0ae0a077 2382 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2383 }
dudmuck 0:8f0d0ae0a077 2384
dudmuck 0:8f0d0ae0a077 2385 memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) );
dudmuck 0:8f0d0ae0a077 2386
dudmuck 2:f2d9aa163652 2387 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_MLMEREQ;
dudmuck 0:8f0d0ae0a077 2388
dudmuck 0:8f0d0ae0a077 2389 switch( mlmeRequest->Type )
dudmuck 0:8f0d0ae0a077 2390 {
dudmuck 0:8f0d0ae0a077 2391 case MLME_JOIN:
dudmuck 0:8f0d0ae0a077 2392 {
dudmuck 0:8f0d0ae0a077 2393 if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
dudmuck 0:8f0d0ae0a077 2394 ( mlmeRequest->Req.Join.AppEui == NULL ) ||
dudmuck 0:8f0d0ae0a077 2395 ( mlmeRequest->Req.Join.AppKey == NULL ) ||
dudmuck 0:8f0d0ae0a077 2396 ( mlmeRequest->Req.Join.NbTrials == 0 ) )
dudmuck 0:8f0d0ae0a077 2397 {
dudmuck 0:8f0d0ae0a077 2398 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2399 }
dudmuck 0:8f0d0ae0a077 2400
dudmuck 0:8f0d0ae0a077 2401 // Enables at least the usage of all datarates.
dudmuck 0:8f0d0ae0a077 2402 if( mlmeRequest->Req.Join.NbTrials < 48 )
dudmuck 0:8f0d0ae0a077 2403 {
dudmuck 0:8f0d0ae0a077 2404 mlmeRequest->Req.Join.NbTrials = 48;
dudmuck 0:8f0d0ae0a077 2405 }
dudmuck 0:8f0d0ae0a077 2406
dudmuck 0:8f0d0ae0a077 2407 LoRaMacFlags.Bits.MlmeReq = 1;
dudmuck 0:8f0d0ae0a077 2408 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
dudmuck 0:8f0d0ae0a077 2409
dudmuck 0:8f0d0ae0a077 2410 LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
dudmuck 0:8f0d0ae0a077 2411 LoRaMacAppEui = mlmeRequest->Req.Join.AppEui;
dudmuck 0:8f0d0ae0a077 2412 LoRaMacAppKey = mlmeRequest->Req.Join.AppKey;
dudmuck 0:8f0d0ae0a077 2413 MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials;
dudmuck 0:8f0d0ae0a077 2414
dudmuck 0:8f0d0ae0a077 2415 // Reset variable JoinRequestTrials
dudmuck 0:8f0d0ae0a077 2416 JoinRequestTrials = 0;
dudmuck 0:8f0d0ae0a077 2417
dudmuck 0:8f0d0ae0a077 2418 // Setup header information
dudmuck 0:8f0d0ae0a077 2419 macHdr.Value = 0;
dudmuck 0:8f0d0ae0a077 2420 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
dudmuck 0:8f0d0ae0a077 2421
dudmuck 0:8f0d0ae0a077 2422 ResetMacParameters( );
Wayne Roberts 29:ad409c68c0a6 2423 LoRaMacFlags.Bits.expecting_beacon = false;
dudmuck 16:915815632c1f 2424 BeaconCtx.state = BEACON_STATE_NONE;
dudmuck 0:8f0d0ae0a077 2425
dudmuck 0:8f0d0ae0a077 2426 Channel = 0; // start with first channel
Wayne Roberts 29:ad409c68c0a6 2427 mac_printf("<ch0>");
Wayne Roberts 29:ad409c68c0a6 2428 mac_printf("mlme-join-send ch%u\r\n", Channel);
dudmuck 0:8f0d0ae0a077 2429 status = Send( &macHdr, 0, NULL, 0 );
dudmuck 0:8f0d0ae0a077 2430 break;
dudmuck 0:8f0d0ae0a077 2431 }
dudmuck 0:8f0d0ae0a077 2432 case MLME_LINK_CHECK:
dudmuck 0:8f0d0ae0a077 2433 {
dudmuck 0:8f0d0ae0a077 2434 LoRaMacFlags.Bits.MlmeReq = 1;
dudmuck 0:8f0d0ae0a077 2435 // LoRaMac will send this command piggy-pack
dudmuck 0:8f0d0ae0a077 2436 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
dudmuck 0:8f0d0ae0a077 2437
dudmuck 0:8f0d0ae0a077 2438 status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
dudmuck 0:8f0d0ae0a077 2439 break;
dudmuck 0:8f0d0ae0a077 2440 }
dudmuck 0:8f0d0ae0a077 2441 case MLME_TXCW:
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 = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout );
dudmuck 0:8f0d0ae0a077 2446 break;
dudmuck 0:8f0d0ae0a077 2447 }
dudmuck 0:8f0d0ae0a077 2448 case MLME_TXCW_1:
dudmuck 0:8f0d0ae0a077 2449 {
dudmuck 0:8f0d0ae0a077 2450 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
dudmuck 0:8f0d0ae0a077 2451 LoRaMacFlags.Bits.MlmeReq = 1;
dudmuck 0:8f0d0ae0a077 2452 status = SetTxContinuousWave1( mlmeRequest->Req.TxCw.Timeout, mlmeRequest->Req.TxCw.Frequency, mlmeRequest->Req.TxCw.Power );
dudmuck 0:8f0d0ae0a077 2453 break;
dudmuck 0:8f0d0ae0a077 2454 }
dudmuck 0:8f0d0ae0a077 2455 default:
dudmuck 0:8f0d0ae0a077 2456 break;
dudmuck 0:8f0d0ae0a077 2457 }
dudmuck 0:8f0d0ae0a077 2458
dudmuck 0:8f0d0ae0a077 2459 if( status != LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 2460 {
Wayne Roberts 29:ad409c68c0a6 2461 LoRaMacFlags.Bits.NodeAckRequested = false;
dudmuck 0:8f0d0ae0a077 2462 LoRaMacFlags.Bits.MlmeReq = 0;
dudmuck 0:8f0d0ae0a077 2463 }
dudmuck 0:8f0d0ae0a077 2464
dudmuck 0:8f0d0ae0a077 2465 return status;
dudmuck 0:8f0d0ae0a077 2466 }
dudmuck 0:8f0d0ae0a077 2467
dudmuck 0:8f0d0ae0a077 2468 LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest )
dudmuck 0:8f0d0ae0a077 2469 {
dudmuck 0:8f0d0ae0a077 2470 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
dudmuck 0:8f0d0ae0a077 2471 LoRaMacHeader_t macHdr;
dudmuck 0:8f0d0ae0a077 2472 uint8_t fPort = 0;
dudmuck 0:8f0d0ae0a077 2473 void *fBuffer;
dudmuck 0:8f0d0ae0a077 2474 uint16_t fBufferSize;
dudmuck 0:8f0d0ae0a077 2475 bool readyToSend = false;
dudmuck 0:8f0d0ae0a077 2476
dudmuck 0:8f0d0ae0a077 2477 if( mcpsRequest == NULL )
dudmuck 0:8f0d0ae0a077 2478 {
dudmuck 0:8f0d0ae0a077 2479 return LORAMAC_STATUS_PARAMETER_INVALID;
dudmuck 0:8f0d0ae0a077 2480 }
dudmuck 0:8f0d0ae0a077 2481
dudmuck 0:8f0d0ae0a077 2482 macHdr.Value = 0;
dudmuck 0:8f0d0ae0a077 2483 memset1 ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) );
dudmuck 2:f2d9aa163652 2484 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_MCPSREQ;
dudmuck 0:8f0d0ae0a077 2485
dudmuck 0:8f0d0ae0a077 2486 switch( mcpsRequest->Type )
dudmuck 0:8f0d0ae0a077 2487 {
dudmuck 0:8f0d0ae0a077 2488 case MCPS_UNCONFIRMED:
dudmuck 0:8f0d0ae0a077 2489 {
dudmuck 0:8f0d0ae0a077 2490 readyToSend = true;
dudmuck 0:8f0d0ae0a077 2491
dudmuck 0:8f0d0ae0a077 2492 macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
dudmuck 0:8f0d0ae0a077 2493 fPort = mcpsRequest->Req.Unconfirmed.fPort;
dudmuck 0:8f0d0ae0a077 2494 fBuffer = mcpsRequest->Req.Unconfirmed.fBuffer;
dudmuck 0:8f0d0ae0a077 2495 fBufferSize = mcpsRequest->Req.Unconfirmed.fBufferSize;
dudmuck 0:8f0d0ae0a077 2496 break;
dudmuck 0:8f0d0ae0a077 2497 }
dudmuck 0:8f0d0ae0a077 2498 case MCPS_CONFIRMED:
dudmuck 0:8f0d0ae0a077 2499 {
dudmuck 0:8f0d0ae0a077 2500 readyToSend = true;
dudmuck 0:8f0d0ae0a077 2501
dudmuck 0:8f0d0ae0a077 2502 macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
dudmuck 0:8f0d0ae0a077 2503 fPort = mcpsRequest->Req.Confirmed.fPort;
dudmuck 0:8f0d0ae0a077 2504 fBuffer = mcpsRequest->Req.Confirmed.fBuffer;
dudmuck 0:8f0d0ae0a077 2505 fBufferSize = mcpsRequest->Req.Confirmed.fBufferSize;
dudmuck 0:8f0d0ae0a077 2506 break;
dudmuck 0:8f0d0ae0a077 2507 }
dudmuck 0:8f0d0ae0a077 2508 case MCPS_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 2509 {
dudmuck 0:8f0d0ae0a077 2510 readyToSend = true;
dudmuck 0:8f0d0ae0a077 2511
dudmuck 0:8f0d0ae0a077 2512 macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
dudmuck 0:8f0d0ae0a077 2513 fBuffer = mcpsRequest->Req.Proprietary.fBuffer;
dudmuck 0:8f0d0ae0a077 2514 fBufferSize = mcpsRequest->Req.Proprietary.fBufferSize;
dudmuck 0:8f0d0ae0a077 2515 break;
dudmuck 0:8f0d0ae0a077 2516 }
dudmuck 0:8f0d0ae0a077 2517 default:
dudmuck 0:8f0d0ae0a077 2518 break;
dudmuck 0:8f0d0ae0a077 2519 }
dudmuck 0:8f0d0ae0a077 2520
Wayne Roberts 29:ad409c68c0a6 2521 if (readyToSend)
dudmuck 0:8f0d0ae0a077 2522 {
dudmuck 0:8f0d0ae0a077 2523 status = Send( &macHdr, fPort, fBuffer, fBufferSize );
Wayne Roberts 29:ad409c68c0a6 2524 if (status == LORAMAC_STATUS_OK)
dudmuck 0:8f0d0ae0a077 2525 {
dudmuck 0:8f0d0ae0a077 2526 McpsConfirm.McpsRequest = mcpsRequest->Type;
dudmuck 0:8f0d0ae0a077 2527 LoRaMacFlags.Bits.McpsReq = 1;
dudmuck 0:8f0d0ae0a077 2528 }
dudmuck 0:8f0d0ae0a077 2529 else
dudmuck 0:8f0d0ae0a077 2530 {
Wayne Roberts 29:ad409c68c0a6 2531 LoRaMacFlags.Bits.NodeAckRequested = false;
dudmuck 0:8f0d0ae0a077 2532 }
dudmuck 0:8f0d0ae0a077 2533 }
dudmuck 0:8f0d0ae0a077 2534
dudmuck 0:8f0d0ae0a077 2535 return status;
dudmuck 0:8f0d0ae0a077 2536 }
dudmuck 0:8f0d0ae0a077 2537
dudmuck 0:8f0d0ae0a077 2538 void LoRaMacTestRxWindowsOn( bool enable )
dudmuck 0:8f0d0ae0a077 2539 {
dudmuck 0:8f0d0ae0a077 2540 IsRxWindowsEnabled = enable;
dudmuck 0:8f0d0ae0a077 2541 }
dudmuck 0:8f0d0ae0a077 2542
dudmuck 0:8f0d0ae0a077 2543 void LoRaMacTestSetMic( uint16_t txPacketCounter )
dudmuck 0:8f0d0ae0a077 2544 {
dudmuck 0:8f0d0ae0a077 2545 UpLinkCounter = txPacketCounter;
dudmuck 16:915815632c1f 2546 //IsUpLinkCounterFixed = true;
dudmuck 0:8f0d0ae0a077 2547 }
dudmuck 0:8f0d0ae0a077 2548
dudmuck 0:8f0d0ae0a077 2549 void LoRaMacTestSetChannel( uint8_t channel )
dudmuck 0:8f0d0ae0a077 2550 {
Wayne Roberts 29:ad409c68c0a6 2551 mac_printf("set-testch%u\r\n", channel);
dudmuck 0:8f0d0ae0a077 2552 Channel = channel;
dudmuck 0:8f0d0ae0a077 2553 }
dudmuck 0:8f0d0ae0a077 2554
dudmuck 0:8f0d0ae0a077 2555
dudmuck 0:8f0d0ae0a077 2556 static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError )
dudmuck 0:8f0d0ae0a077 2557 {
Wayne Roberts 29:ad409c68c0a6 2558 RxConfigParams_t rxConfigParams = { 0, 0 };
dudmuck 0:8f0d0ae0a077 2559 double tSymbol = 0.0;
dudmuck 0:8f0d0ae0a077 2560
dudmuck 0:8f0d0ae0a077 2561 rxConfigParams.Datarate = datarate;
dudmuck 0:8f0d0ae0a077 2562
dudmuck 0:8f0d0ae0a077 2563 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
dudmuck 0:8f0d0ae0a077 2564 if( datarate == DR_7 )
dudmuck 0:8f0d0ae0a077 2565 { // FSK
dudmuck 0:8f0d0ae0a077 2566 tSymbol = ( 1.0 / ( double )Datarates[datarate] ) * 8.0; // 1 symbol equals 1 byte
dudmuck 0:8f0d0ae0a077 2567 }
dudmuck 0:8f0d0ae0a077 2568 else
dudmuck 0:8f0d0ae0a077 2569 #endif
dudmuck 0:8f0d0ae0a077 2570 { // LoRa
Wayne Roberts 29:ad409c68c0a6 2571 tSymbol = ( ( double )( 1 << Datarates[datarate] ) / LORA_BANDWIDTH_KHZ ) * 1e3;
dudmuck 0:8f0d0ae0a077 2572 }
dudmuck 0:8f0d0ae0a077 2573
dudmuck 0:8f0d0ae0a077 2574 rxConfigParams.RxWindowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * LoRaMacParams.MinRxSymbols - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), LoRaMacParams.MinRxSymbols ); // Computed number of symbols
Wayne Roberts 29:ad409c68c0a6 2575 mac_printf("RxWindowTimeout:%u\r\n", rxConfigParams.RxWindowTimeout);
dudmuck 0:8f0d0ae0a077 2576
dudmuck 0:8f0d0ae0a077 2577 return rxConfigParams;
dudmuck 0:8f0d0ae0a077 2578 }
dudmuck 0:8f0d0ae0a077 2579
dudmuck 20:42839629a5dc 2580 void LoRaMacBottomHalf()
dudmuck 20:42839629a5dc 2581 {
Wayne Roberts 29:ad409c68c0a6 2582 if (LoRaMacFlags.Bits.join_send) {
Wayne Roberts 29:ad409c68c0a6 2583 join_send_bh();
Wayne Roberts 29:ad409c68c0a6 2584 LoRaMacFlags.Bits.join_send = 0;
dudmuck 20:42839629a5dc 2585 }
Wayne Roberts 29:ad409c68c0a6 2586 if (LoRaMacFlags.Bits.send) {
Wayne Roberts 29:ad409c68c0a6 2587 send_bh();
Wayne Roberts 29:ad409c68c0a6 2588 LoRaMacFlags.Bits.send = 0;
dudmuck 20:42839629a5dc 2589 }
Wayne Roberts 29:ad409c68c0a6 2590
Wayne Roberts 29:ad409c68c0a6 2591 if (LoRaMacFlags.Bits.reJoin) {
Wayne Roberts 29:ad409c68c0a6 2592 MlmeReq_t mlmeReq;
Wayne Roberts 29:ad409c68c0a6 2593 mlmeReq.Type = MLME_JOIN;
Wayne Roberts 29:ad409c68c0a6 2594
Wayne Roberts 29:ad409c68c0a6 2595 mlmeReq.Req.Join.DevEui = LoRaMacDevEui;
Wayne Roberts 29:ad409c68c0a6 2596 mlmeReq.Req.Join.AppEui = LoRaMacAppEui;
Wayne Roberts 29:ad409c68c0a6 2597 mlmeReq.Req.Join.AppKey = LoRaMacAppKey;
Wayne Roberts 29:ad409c68c0a6 2598 mlmeReq.Req.Join.NbTrials = 255;
Wayne Roberts 29:ad409c68c0a6 2599
Wayne Roberts 29:ad409c68c0a6 2600 if (LoRaMacMlmeRequest(&mlmeReq) == LORAMAC_STATUS_OK)
Wayne Roberts 29:ad409c68c0a6 2601 LoRaMacFlags.Bits.reJoin = 0;
dudmuck 20:42839629a5dc 2602 }
Wayne Roberts 29:ad409c68c0a6 2603
Wayne Roberts 29:ad409c68c0a6 2604 Radio::service();
dudmuck 20:42839629a5dc 2605 }