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:
Wed Aug 02 11:42:33 2017 -0700
Revision:
18:9ac71c0eb70d
Parent:
17:3215f12051f9
Child:
20:42839629a5dc
add pwm commands and 434MHz band

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