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.
command | arguments | description |
---|---|---|
? | - | print available commands |
. (period) | - | print status (DevEUI, DevAddr, etc) |
ul | length integer | set 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: button | RX TX: (unused) | A3 A4: Rotary Angle Sensor |
D6 D7: RGB LED | SCL SDA: digital light sensor | A1 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.
mac/LoRaMac.cpp@13:18de9ee3a461, 2017-07-08 (annotated)
- 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?
User | Revision | Line number | New 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 |