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 Jul 28 22:18:46 2017 +0000
Revision:
17:3215f12051f9
Parent:
16:915815632c1f
Child:
18:9ac71c0eb70d
handle stalled beacon reception in application layer

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