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:
Sat Jul 08 00:35:03 2017 +0000
Revision:
13:18de9ee3a461
Parent:
12:ed33c53afcaf
Child:
14:7ac0add1123e
gateway-tx debug input pin, discard timer error on missed beacon

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