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:
dudmuck
Date:
Fri Aug 04 13:23:38 2017 -0700
Revision:
20:42839629a5dc
Parent:
18:9ac71c0eb70d
Child:
21:500ff43d8424
add sleep() call, mbedignore rtos

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