LoRaWAN end device MAC layer for SX1272 and SX1276. Supports LoRaWAN-1.0 and LoRaWAN-1.1

Dependencies:   sx12xx_hal

Dependents:   LoRaWAN-SanJose_Bootcamp LoRaWAN-grove-cayenne LoRaWAN-classC-demo LoRaWAN-grove-cayenne ... more

radio chip selection

Radio chip driver is not included, because two options are available.
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 NAmote72 or Murata discovery, then you must import only sx127x driver.

application project requirements

This library requires mbed TLS to be enabled.
The file mbed_app.json must be present in the project using this library:

{
    "macros": [ "MBEDTLS_CMAC_C" ]
}

regional PHY selection

All end device configuration is done in Commissioning.h, define desired radio frequency band of operation in this header file.
Commissioning.h is located in the application using this library.

end device provisioning

End device is provisioned by editing Commissioning.h in the application which is using this library
To use LoRaWAN-1.0 OTA: make sure LORAWAN_ROOT_APPKEY is undefined.
To use LoRaWAN-1.1 OTA, define LORAWAN_ROOT_APPKEY.
To select OTA operation, define LORAWAN_JOIN_EUI, then LORAWAN_DEVICE_EUI must be defined, along with root key(s).
To select ABP operation, undefine LORAWAN_JOIN_EUI: then define session keys

LoRaWAN 1.0 nameLoRaWAN 1.1 nameComissioning.h defnedescription
OTADevEUIDevEUILORAWAN_DEVICE_EUIuniquely identifies end device
OTAAppEUIJoinEUILORAWAN_JOIN_EUI
OTAAppKeyNwkKeyLORAWAN_ROOT_NWKKEYroot key for network server
OTA(note 1)AppKeyLORAWAN_ROOT_APPKEYroot key for application server
ABPNwkSKey(note 3)LORAWAN_FNwkSIntKeynetwork session key
ABP(note 2)SNwkSIntKeyLORAWAN_SNwkSIntKeymac layer network integrity key
ABP(note 2)NwkSEncKeyLORAWAN_NwkSEncKeynetwork session encryption key
ABP(note 2)FNwkSIntKeyLORAWAN_FNwkSIntKeyforwarding network session integrity key
ABPAppSKeyAppSKeyLORAWAN_APPSKEYapplication session encryption key

(note 1): LoRaWAN-1.0 OTA uses a single root key for both network server and application server.

In LoRaWAN-1.0 OTA: the single root AppKey is used to generate NwkSkey and AppSKey.
(note 2): In LoRaWAN-1.0 (both OTA and ABP) SNwkSIntKey, NwkSEncKey. FNwkSIntKey are of same value and are collectively known as NwkSKey.
(note 3): LoRaWAN-1.0 uses single network session key, LoRaWAN-1.1 uses 3 network session keys. Both use a unique application session key.


In LoRaWAN-1.1 OTA: the root NwkKey is used to generate SNwkSIntKey, NwkSEncKey, FNwkSIntKey
In LoRaWAN-1.1 OTA: the root AppKey is used to generate AppSKey


in ABP mode, the DevAddr, and session keys are fixed (never change), and frame counters never reset to zero.
ABP operation has no concept of: root keys, or DevEUI or JoinEUI/AppEUI.
in OTA mode, the DevAddr and session keys are assigned at join procedure, and frame counters reset at join.

eeprom

This library includes eeprom driver to support non-volatile storage required by LoRaWAN specification.
Currently eeprom is implemented for STM32L1 family and STM32L0 family.
Writing of values are wear-leveled to increase endurance; each write operation circulates across several memory locations. A read operation returns the highest value found. This simple method is used for sequence numbers which only increase.

value nameused in
DevNonceOTAfor Join request (note 1)
RJcount1OTAfor ReJoin Type 1 request
FCntUpABPuplink frame counter
NFCntDownABPdownlink frame counter
AFCntDownABPdownlink frame counter

AFCntDown is only used in LoRaWAN-1.1 when application payload is present in downlink and FPort > 0.
NFCntDown is used in LoRaWAN-1.1 when FPort is zero in downlink or application payload not present.
NFCntDown is the only downlink frame counter used in LoRaWAN-1.0
(note 1) OTA DevNonce is random number in LoRaWAN-1.0, therefore not stored in eeprom. DevNonce in LoRaWAN-1.1 is forever increasing (non-volatile) number upon each join request,.
RJcount0 is only stored in RAM because the value resets upon new session from JoinAccept, therefore not stored in eeprom.
Frame counters in OTA mode reset upon new session in join request, therefore are stored in RAM instead of eeprom for OTA.

radio driver support

When SX127x driver is used, both SX1272 and SX1276 are supported without defining at compile time. The chip is detected at start-up.
Supported radio platforms:


Alternately, when SX126x driver is imported, the SX126xDVK1xAS board is used.

low-speed clock oscillator selection

LoRaWAN uses 32768Hz crystal to permit low-power operation.
However, some mbed targets might revert to low-speed internal oscillator, which is not accurate enough for LoRaWAN operation.
An oscillator check is performed at initialization; program will not start if internal oscillator is used.
To force LSE watch crystal, add to mbed_app.json

{
    "macros": [ "MBEDTLS_CMAC_C" ],
    "target_overrides": {
        "<your-target>": {
            "target.lse_available": true
        }
    }
}
Committer:
Wayne Roberts
Date:
Wed May 23 10:20:07 2018 -0700
Revision:
8:5a5ea7cc946f
Parent:
7:4b6f960dcca2
Child:
10:9a7a8b8d0ac2
permit either sx127x or sx126x radio chips to be used

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:6b3ac9c5a042 1
Wayne Roberts 0:6b3ac9c5a042 2 #include "LoRaMacPrivate.h"
Wayne Roberts 0:6b3ac9c5a042 3 #include "LoRaMacCrypto.h"
Wayne Roberts 0:6b3ac9c5a042 4
Wayne Roberts 3:eb174e10afbb 5 //#define ADR_ACK_LIMIT 64
Wayne Roberts 3:eb174e10afbb 6 //#define ADR_ACK_DELAY 32
Wayne Roberts 0:6b3ac9c5a042 7 #define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4)
Wayne Roberts 0:6b3ac9c5a042 8 #define RECEIVE_DELAY1_us 1000000
Wayne Roberts 0:6b3ac9c5a042 9 #define LORAMAC_MFR_LEN 4
Wayne Roberts 0:6b3ac9c5a042 10
Wayne Roberts 0:6b3ac9c5a042 11 /*!
Wayne Roberts 0:6b3ac9c5a042 12 * LoRaMAC Battery level indicator
Wayne Roberts 0:6b3ac9c5a042 13 */
Wayne Roberts 0:6b3ac9c5a042 14 typedef enum eLoRaMacBatteryLevel
Wayne Roberts 0:6b3ac9c5a042 15 {
Wayne Roberts 0:6b3ac9c5a042 16 /*!
Wayne Roberts 0:6b3ac9c5a042 17 * External power source
Wayne Roberts 0:6b3ac9c5a042 18 */
Wayne Roberts 0:6b3ac9c5a042 19 BAT_LEVEL_EXT_SRC = 0x00,
Wayne Roberts 0:6b3ac9c5a042 20 /*!
Wayne Roberts 0:6b3ac9c5a042 21 * Battery level empty
Wayne Roberts 0:6b3ac9c5a042 22 */
Wayne Roberts 0:6b3ac9c5a042 23 BAT_LEVEL_EMPTY = 0x01,
Wayne Roberts 0:6b3ac9c5a042 24 /*!
Wayne Roberts 0:6b3ac9c5a042 25 * Battery level full
Wayne Roberts 0:6b3ac9c5a042 26 */
Wayne Roberts 0:6b3ac9c5a042 27 BAT_LEVEL_FULL = 0xFE,
Wayne Roberts 0:6b3ac9c5a042 28 /*!
Wayne Roberts 0:6b3ac9c5a042 29 * Battery level - no measurement available
Wayne Roberts 0:6b3ac9c5a042 30 */
Wayne Roberts 0:6b3ac9c5a042 31 BAT_LEVEL_NO_MEASURE = 0xFF,
Wayne Roberts 0:6b3ac9c5a042 32 }LoRaMacBatteryLevel_t;
Wayne Roberts 0:6b3ac9c5a042 33
Wayne Roberts 0:6b3ac9c5a042 34 /*!
Wayne Roberts 0:6b3ac9c5a042 35 * LoRaMac internal state
Wayne Roberts 0:6b3ac9c5a042 36 */
Wayne Roberts 0:6b3ac9c5a042 37 flags_t flags;
Wayne Roberts 0:6b3ac9c5a042 38
Wayne Roberts 0:6b3ac9c5a042 39 void (*function_pending)(void); // one-shot
Wayne Roberts 0:6b3ac9c5a042 40
Wayne Roberts 0:6b3ac9c5a042 41 /*!
Wayne Roberts 0:6b3ac9c5a042 42 * Current channel index
Wayne Roberts 0:6b3ac9c5a042 43 */
Wayne Roberts 0:6b3ac9c5a042 44 uint8_t Channel;
Wayne Roberts 0:6b3ac9c5a042 45
Wayne Roberts 0:6b3ac9c5a042 46 static MlmeIndication_t MlmeIndication;
Wayne Roberts 0:6b3ac9c5a042 47 static MlmeConfirm_t MlmeConfirm;
Wayne Roberts 0:6b3ac9c5a042 48 static McpsIndication_t McpsIndication;
Wayne Roberts 0:6b3ac9c5a042 49 static McpsConfirm_t McpsConfirm;
Wayne Roberts 0:6b3ac9c5a042 50
Wayne Roberts 0:6b3ac9c5a042 51 uint32_t LoRaMacDevAddr;
Wayne Roberts 0:6b3ac9c5a042 52 uint32_t LoRaMacNetID;
Wayne Roberts 0:6b3ac9c5a042 53 static skey_t keys;
Wayne Roberts 0:6b3ac9c5a042 54
Wayne Roberts 0:6b3ac9c5a042 55 uint8_t MacCommandsBufferToRepeatIndex;
Wayne Roberts 0:6b3ac9c5a042 56 uint8_t MacCommandsBufferIndex;
Wayne Roberts 0:6b3ac9c5a042 57 uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
Wayne Roberts 0:6b3ac9c5a042 58 static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH];
Wayne Roberts 0:6b3ac9c5a042 59
Wayne Roberts 0:6b3ac9c5a042 60 LoRaMacParams_t LoRaMacParams;
Wayne Roberts 0:6b3ac9c5a042 61
Wayne Roberts 0:6b3ac9c5a042 62 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 63 static const uint8_t *LoRaMacDevEui;
Wayne Roberts 0:6b3ac9c5a042 64 static const uint8_t *LoRaMacJoinEui;
Wayne Roberts 0:6b3ac9c5a042 65 static const uint8_t *RootNwkKey;
Wayne Roberts 0:6b3ac9c5a042 66 static const uint8_t *RootAppKey;
Wayne Roberts 0:6b3ac9c5a042 67 static uint8_t MaxJoinRequestTrials;
Wayne Roberts 0:6b3ac9c5a042 68 static uint8_t JSEncKey[16]; // TODO move to keys
Wayne Roberts 0:6b3ac9c5a042 69 static uint8_t JSIntKey[16]; // TODO move to keys
Wayne Roberts 0:6b3ac9c5a042 70 static uint8_t JoinReqType;
Wayne Roberts 0:6b3ac9c5a042 71 static uint16_t LoRaMacDevNonce;
Wayne Roberts 0:6b3ac9c5a042 72 uint16_t RJcount0;
Wayne Roberts 0:6b3ac9c5a042 73
Wayne Roberts 0:6b3ac9c5a042 74 static uint32_t FCntUp;
Wayne Roberts 0:6b3ac9c5a042 75 static uint32_t NFCntDown; /**< set to next expected value */
Wayne Roberts 0:6b3ac9c5a042 76 static uint32_t AFCntDown; /**< set to next expected value */
Wayne Roberts 0:6b3ac9c5a042 77 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 78
Wayne Roberts 3:eb174e10afbb 79 static uint16_t ADR_ACK_LIMIT;
Wayne Roberts 3:eb174e10afbb 80 static uint16_t ADR_ACK_DELAY;
Wayne Roberts 3:eb174e10afbb 81
Wayne Roberts 0:6b3ac9c5a042 82 DeviceClass_t LoRaMacDeviceClass;
Wayne Roberts 0:6b3ac9c5a042 83 uint8_t tx_buf_len;
Wayne Roberts 0:6b3ac9c5a042 84 const LoRaMacHeader_t* uplinkMHDR = (LoRaMacHeader_t*)&Radio::radio.tx_buf[0];
Wayne Roberts 0:6b3ac9c5a042 85
Wayne Roberts 0:6b3ac9c5a042 86 static uint32_t RxWindow1Delay_us;
Wayne Roberts 0:6b3ac9c5a042 87 static uint32_t RxWindow2Delay_us;
Wayne Roberts 0:6b3ac9c5a042 88
Wayne Roberts 0:6b3ac9c5a042 89 LoRaMacHeader_t last_up_macHdr;
Wayne Roberts 0:6b3ac9c5a042 90 static uint8_t rxFRMPayload[244];
Wayne Roberts 0:6b3ac9c5a042 91
Wayne Roberts 0:6b3ac9c5a042 92 static const LoRaMacPrimitives_t *LoRaMacPrimitives;
Wayne Roberts 0:6b3ac9c5a042 93 static const LoRaMacCallback_t *LoRaMacCallbacks;
Wayne Roberts 0:6b3ac9c5a042 94
Wayne Roberts 0:6b3ac9c5a042 95 /*!
Wayne Roberts 0:6b3ac9c5a042 96 * LoRaMAC frame counter. Each time a packet is received the counter is incremented.
Wayne Roberts 0:6b3ac9c5a042 97 * Only the 16 LSB bits are received
Wayne Roberts 0:6b3ac9c5a042 98 */
Wayne Roberts 0:6b3ac9c5a042 99 static uint16_t ConfFCntDown;
Wayne Roberts 0:6b3ac9c5a042 100 static uint16_t ConfFCntUp;
Wayne Roberts 0:6b3ac9c5a042 101
Wayne Roberts 0:6b3ac9c5a042 102 static void PrepareRxDoneAbort(LoRaMacEventInfoStatus_t);
Wayne Roberts 0:6b3ac9c5a042 103
Wayne Roberts 7:4b6f960dcca2 104 void OnRadioRxTimeout(void);
Wayne Roberts 7:4b6f960dcca2 105
Wayne Roberts 0:6b3ac9c5a042 106 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 107 AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
Wayne Roberts 0:6b3ac9c5a042 108 {
Wayne Roberts 0:6b3ac9c5a042 109 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 110 // The maximum buffer length must take MAC commands to re-send into account.
Wayne Roberts 0:6b3ac9c5a042 111 uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex;
Wayne Roberts 0:6b3ac9c5a042 112
Wayne Roberts 0:6b3ac9c5a042 113 MAC_PRINTF("AddMacCommand(%02x, %02x, %02x)\r\n", cmd, p1, p2);
Wayne Roberts 0:6b3ac9c5a042 114 switch( cmd )
Wayne Roberts 0:6b3ac9c5a042 115 {
Wayne Roberts 0:6b3ac9c5a042 116 case MOTE_MAC_LINK_CHECK_REQ:
Wayne Roberts 0:6b3ac9c5a042 117 case MOTE_MAC_DEVICE_TIME_REQ:
Wayne Roberts 0:6b3ac9c5a042 118 if( MacCommandsBufferIndex < bufLen )
Wayne Roberts 0:6b3ac9c5a042 119 {
Wayne Roberts 0:6b3ac9c5a042 120 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 121 // No payload for this command
Wayne Roberts 0:6b3ac9c5a042 122 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 123 }
Wayne Roberts 0:6b3ac9c5a042 124 break;
Wayne Roberts 0:6b3ac9c5a042 125 case MOTE_MAC_LINK_ADR_ANS:
Wayne Roberts 0:6b3ac9c5a042 126 if( MacCommandsBufferIndex < ( bufLen - 1 ) )
Wayne Roberts 0:6b3ac9c5a042 127 {
Wayne Roberts 0:6b3ac9c5a042 128 MAC_PRINTF("LINK_ADR_ANS %02x ", p1);
Wayne Roberts 0:6b3ac9c5a042 129 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 130 // Margin
Wayne Roberts 0:6b3ac9c5a042 131 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Wayne Roberts 0:6b3ac9c5a042 132 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 133 }
Wayne Roberts 0:6b3ac9c5a042 134 break;
Wayne Roberts 0:6b3ac9c5a042 135 case MOTE_MAC_DUTY_CYCLE_ANS:
Wayne Roberts 0:6b3ac9c5a042 136 if( MacCommandsBufferIndex < bufLen )
Wayne Roberts 0:6b3ac9c5a042 137 {
Wayne Roberts 0:6b3ac9c5a042 138 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 139 // No payload for this answer
Wayne Roberts 0:6b3ac9c5a042 140 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 141 }
Wayne Roberts 0:6b3ac9c5a042 142 break;
Wayne Roberts 0:6b3ac9c5a042 143 case MOTE_MAC_RX_PARAM_SETUP_ANS:
Wayne Roberts 0:6b3ac9c5a042 144 if( MacCommandsBufferIndex < ( bufLen - 1 ) )
Wayne Roberts 0:6b3ac9c5a042 145 {
Wayne Roberts 0:6b3ac9c5a042 146 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 147 // Status: Datarate ACK, Channel ACK
Wayne Roberts 0:6b3ac9c5a042 148 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Wayne Roberts 0:6b3ac9c5a042 149 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 150 }
Wayne Roberts 0:6b3ac9c5a042 151 break;
Wayne Roberts 0:6b3ac9c5a042 152 case MOTE_MAC_DEV_STATUS_ANS:
Wayne Roberts 0:6b3ac9c5a042 153 if( MacCommandsBufferIndex < ( bufLen - 2 ) )
Wayne Roberts 0:6b3ac9c5a042 154 {
Wayne Roberts 0:6b3ac9c5a042 155 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 156 // 1st byte Battery
Wayne Roberts 0:6b3ac9c5a042 157 // 2nd byte Margin
Wayne Roberts 0:6b3ac9c5a042 158 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Wayne Roberts 0:6b3ac9c5a042 159 MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
Wayne Roberts 0:6b3ac9c5a042 160 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 161 }
Wayne Roberts 0:6b3ac9c5a042 162 break;
Wayne Roberts 0:6b3ac9c5a042 163 case MOTE_MAC_NEW_CHANNEL_ANS:
Wayne Roberts 0:6b3ac9c5a042 164 if( MacCommandsBufferIndex < ( bufLen - 1 ) )
Wayne Roberts 0:6b3ac9c5a042 165 {
Wayne Roberts 0:6b3ac9c5a042 166 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 167 // Status: Datarate range OK, Channel frequency OK
Wayne Roberts 0:6b3ac9c5a042 168 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Wayne Roberts 0:6b3ac9c5a042 169 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 170 }
Wayne Roberts 0:6b3ac9c5a042 171 break;
Wayne Roberts 0:6b3ac9c5a042 172 case MOTE_MAC_RX_TIMING_SETUP_ANS:
Wayne Roberts 0:6b3ac9c5a042 173 if( MacCommandsBufferIndex < bufLen )
Wayne Roberts 0:6b3ac9c5a042 174 {
Wayne Roberts 0:6b3ac9c5a042 175 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 176 // No payload for this answer
Wayne Roberts 0:6b3ac9c5a042 177 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 178 }
Wayne Roberts 0:6b3ac9c5a042 179 break;
Wayne Roberts 0:6b3ac9c5a042 180 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 181 case MOTE_MAC_REKEY_IND:
Wayne Roberts 0:6b3ac9c5a042 182 if( MacCommandsBufferIndex < bufLen-1 )
Wayne Roberts 0:6b3ac9c5a042 183 {
Wayne Roberts 0:6b3ac9c5a042 184 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 185 // minor version:
Wayne Roberts 0:6b3ac9c5a042 186 if (RootAppKey == NULL)
Wayne Roberts 0:6b3ac9c5a042 187 MacCommandsBuffer[MacCommandsBufferIndex++] = 0; // lorawan1v0
Wayne Roberts 0:6b3ac9c5a042 188 else
Wayne Roberts 0:6b3ac9c5a042 189 MacCommandsBuffer[MacCommandsBufferIndex++] = 1; // lorawan1v1
Wayne Roberts 0:6b3ac9c5a042 190
Wayne Roberts 0:6b3ac9c5a042 191 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 192 }
Wayne Roberts 0:6b3ac9c5a042 193 break;
Wayne Roberts 0:6b3ac9c5a042 194 case MOTE_MAC_REJOIN_PARAM_ANS:
Wayne Roberts 0:6b3ac9c5a042 195 if( MacCommandsBufferIndex < bufLen-1 )
Wayne Roberts 0:6b3ac9c5a042 196 {
Wayne Roberts 0:6b3ac9c5a042 197 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 198 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Wayne Roberts 0:6b3ac9c5a042 199 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 200 }
Wayne Roberts 0:6b3ac9c5a042 201 break;
Wayne Roberts 0:6b3ac9c5a042 202 #else
Wayne Roberts 0:6b3ac9c5a042 203 case MOTE_MAC_RESET_IND:
Wayne Roberts 0:6b3ac9c5a042 204 if( MacCommandsBufferIndex < bufLen-1 )
Wayne Roberts 0:6b3ac9c5a042 205 {
Wayne Roberts 0:6b3ac9c5a042 206 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 0:6b3ac9c5a042 207 // minor version:
Wayne Roberts 0:6b3ac9c5a042 208 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Wayne Roberts 0:6b3ac9c5a042 209 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 210 }
Wayne Roberts 0:6b3ac9c5a042 211 break;
Wayne Roberts 0:6b3ac9c5a042 212 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 7:4b6f960dcca2 213 case MOTE_MAC_MODE_IND:
Wayne Roberts 7:4b6f960dcca2 214 if( MacCommandsBufferIndex < bufLen-1 )
Wayne Roberts 7:4b6f960dcca2 215 {
Wayne Roberts 7:4b6f960dcca2 216 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
Wayne Roberts 7:4b6f960dcca2 217 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
Wayne Roberts 7:4b6f960dcca2 218 status = LORAMAC_STATUS_OK;
Wayne Roberts 7:4b6f960dcca2 219 }
Wayne Roberts 7:4b6f960dcca2 220 break;
Wayne Roberts 0:6b3ac9c5a042 221 default:
Wayne Roberts 0:6b3ac9c5a042 222 MAC_PRINTF("unknown-addCmd %02x\r\n", cmd);
Wayne Roberts 0:6b3ac9c5a042 223 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 224 } // ..switch( cmd )
Wayne Roberts 0:6b3ac9c5a042 225
Wayne Roberts 0:6b3ac9c5a042 226 if( status == LORAMAC_STATUS_OK )
Wayne Roberts 0:6b3ac9c5a042 227 {
Wayne Roberts 0:6b3ac9c5a042 228 flags.MacCommandsInNextTx = true;
Wayne Roberts 0:6b3ac9c5a042 229 }
Wayne Roberts 0:6b3ac9c5a042 230 return status;
Wayne Roberts 0:6b3ac9c5a042 231 } // ..AddMacCommand()
Wayne Roberts 0:6b3ac9c5a042 232
Wayne Roberts 0:6b3ac9c5a042 233
Wayne Roberts 0:6b3ac9c5a042 234 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout )
Wayne Roberts 0:6b3ac9c5a042 235 {
Wayne Roberts 0:6b3ac9c5a042 236 int8_t txPowerIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 237 int8_t txPower = 0;
Wayne Roberts 0:6b3ac9c5a042 238
Wayne Roberts 3:eb174e10afbb 239 txPowerIndex = region_LimitTxPower( LoRaMacParams.ChannelsTxPower );
Wayne Roberts 0:6b3ac9c5a042 240 txPower = TxPowers[txPowerIndex];
Wayne Roberts 0:6b3ac9c5a042 241
Wayne Roberts 0:6b3ac9c5a042 242 Radio::SetTxContinuousWave( Channels[Channel].FreqHz, txPower, timeout );
Wayne Roberts 0:6b3ac9c5a042 243
Wayne Roberts 0:6b3ac9c5a042 244 flags.uplink_in_progress = 1;
Wayne Roberts 0:6b3ac9c5a042 245
Wayne Roberts 0:6b3ac9c5a042 246 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 247 }
Wayne Roberts 0:6b3ac9c5a042 248
Wayne Roberts 0:6b3ac9c5a042 249 __attribute__((weak)) LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 250 LoRaMacMlmeRequestClassB( const MlmeReq_t *mlmeRequest )
Wayne Roberts 0:6b3ac9c5a042 251 {
Wayne Roberts 0:6b3ac9c5a042 252 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 253 }
Wayne Roberts 0:6b3ac9c5a042 254
Wayne Roberts 0:6b3ac9c5a042 255 __attribute__((weak)) LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 256 AddMacCommandClassB( uint8_t cmd, uint8_t p1, uint8_t p2 )
Wayne Roberts 0:6b3ac9c5a042 257 {
Wayne Roberts 0:6b3ac9c5a042 258 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 259 }
Wayne Roberts 0:6b3ac9c5a042 260
Wayne Roberts 0:6b3ac9c5a042 261 __attribute__((weak)) void
Wayne Roberts 0:6b3ac9c5a042 262 ResetMacParametersClassB()
Wayne Roberts 0:6b3ac9c5a042 263 {
Wayne Roberts 0:6b3ac9c5a042 264 }
Wayne Roberts 0:6b3ac9c5a042 265
Wayne Roberts 0:6b3ac9c5a042 266 static void ResetMacParameters( void )
Wayne Roberts 0:6b3ac9c5a042 267 {
Wayne Roberts 0:6b3ac9c5a042 268 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 269 flags.IsLoRaMacNetworkJoined = 0;
Wayne Roberts 0:6b3ac9c5a042 270 NFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 271 AFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 272 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 273
Wayne Roberts 0:6b3ac9c5a042 274 #ifdef DUTY_ENABLE
Wayne Roberts 0:6b3ac9c5a042 275 DutyInit();
Wayne Roberts 0:6b3ac9c5a042 276 #endif /* DUTY_ENABLE */
Wayne Roberts 0:6b3ac9c5a042 277
Wayne Roberts 0:6b3ac9c5a042 278 MacCommandsBufferIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 279 MacCommandsBufferToRepeatIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 280
Wayne Roberts 0:6b3ac9c5a042 281 //IsRxWindowsEnabled = true;
Wayne Roberts 0:6b3ac9c5a042 282
Wayne Roberts 0:6b3ac9c5a042 283 LoRaMacParams.ChannelsTxPower = LoRaMacParamsDefaults.ChannelsTxPower;
Wayne Roberts 0:6b3ac9c5a042 284 LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 285
Wayne Roberts 0:6b3ac9c5a042 286 LoRaMacParams.MaxRxWindow_us = LoRaMacParamsDefaults.MaxRxWindow_us;
Wayne Roberts 0:6b3ac9c5a042 287 LoRaMacParams.ReceiveDelay1_us = LoRaMacParamsDefaults.ReceiveDelay1_us;
Wayne Roberts 0:6b3ac9c5a042 288 LoRaMacParams.ReceiveDelay2_us = LoRaMacParamsDefaults.ReceiveDelay2_us;
Wayne Roberts 0:6b3ac9c5a042 289 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 290 LoRaMacParams.JoinAcceptDelay1_us = LoRaMacParamsDefaults.JoinAcceptDelay1_us;
Wayne Roberts 0:6b3ac9c5a042 291 LoRaMacParams.JoinAcceptDelay2_us = LoRaMacParamsDefaults.JoinAcceptDelay2_us;
Wayne Roberts 0:6b3ac9c5a042 292 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 293
Wayne Roberts 0:6b3ac9c5a042 294 LoRaMacParams.Rx1DrOffset = LoRaMacParamsDefaults.Rx1DrOffset;
Wayne Roberts 0:6b3ac9c5a042 295 LoRaMacParams.NbTrans = LoRaMacParamsDefaults.NbTrans;
Wayne Roberts 0:6b3ac9c5a042 296
Wayne Roberts 0:6b3ac9c5a042 297 LoRaMacParams.Rx2Channel = LoRaMacParamsDefaults.Rx2Channel;
Wayne Roberts 0:6b3ac9c5a042 298
Wayne Roberts 0:6b3ac9c5a042 299 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
Wayne Roberts 3:eb174e10afbb 300 LoRaMacParams.NbEnabledChannels = LoRaMacParamsDefaults.NbEnabledChannels;
Wayne Roberts 0:6b3ac9c5a042 301
Wayne Roberts 0:6b3ac9c5a042 302 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 303 memcpy( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
Wayne Roberts 0:6b3ac9c5a042 304 #endif
Wayne Roberts 0:6b3ac9c5a042 305
Wayne Roberts 7:4b6f960dcca2 306 LoRaMacParams.MaxListenTime = LoRaMacParamsDefaults.MaxListenTime;
Wayne Roberts 7:4b6f960dcca2 307
Wayne Roberts 0:6b3ac9c5a042 308
Wayne Roberts 0:6b3ac9c5a042 309 flags.SrvAckRequested = false;
Wayne Roberts 0:6b3ac9c5a042 310 flags.MacCommandsInNextTx = false;
Wayne Roberts 0:6b3ac9c5a042 311
Wayne Roberts 0:6b3ac9c5a042 312 // Initialize channel index.
Wayne Roberts 0:6b3ac9c5a042 313 Channel = LORA_MAX_NB_CHANNELS;
Wayne Roberts 0:6b3ac9c5a042 314
Wayne Roberts 0:6b3ac9c5a042 315 ResetMacParametersClassB();
Wayne Roberts 0:6b3ac9c5a042 316
Wayne Roberts 0:6b3ac9c5a042 317 } // ..ResetMacParameters()
Wayne Roberts 0:6b3ac9c5a042 318
Wayne Roberts 0:6b3ac9c5a042 319 static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
Wayne Roberts 0:6b3ac9c5a042 320 {
Wayne Roberts 0:6b3ac9c5a042 321 uint16_t maxN = 0;
Wayne Roberts 0:6b3ac9c5a042 322 uint8_t payloadSize;
Wayne Roberts 0:6b3ac9c5a042 323
Wayne Roberts 0:6b3ac9c5a042 324 // Get the maximum payload length
Wayne Roberts 0:6b3ac9c5a042 325 maxN = MaxPayloadOfDatarate[datarate];
Wayne Roberts 0:6b3ac9c5a042 326
Wayne Roberts 0:6b3ac9c5a042 327 // Calculate the resulting payload size
Wayne Roberts 0:6b3ac9c5a042 328 payloadSize = ( lenN + fOptsLen );
Wayne Roberts 0:6b3ac9c5a042 329
Wayne Roberts 0:6b3ac9c5a042 330 // Validation of the application payload size
Wayne Roberts 0:6b3ac9c5a042 331 if( payloadSize <= maxN )
Wayne Roberts 0:6b3ac9c5a042 332 {
Wayne Roberts 0:6b3ac9c5a042 333 return true;
Wayne Roberts 0:6b3ac9c5a042 334 }
Wayne Roberts 0:6b3ac9c5a042 335 return false;
Wayne Roberts 0:6b3ac9c5a042 336 }
Wayne Roberts 0:6b3ac9c5a042 337
Wayne Roberts 0:6b3ac9c5a042 338 static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut )
Wayne Roberts 0:6b3ac9c5a042 339 {
Wayne Roberts 0:6b3ac9c5a042 340 uint8_t i = 0;
Wayne Roberts 0:6b3ac9c5a042 341 uint8_t cmdCount = 0;
Wayne Roberts 0:6b3ac9c5a042 342
Wayne Roberts 0:6b3ac9c5a042 343 if( ( cmdBufIn == NULL ) || ( cmdBufOut == NULL ) )
Wayne Roberts 0:6b3ac9c5a042 344 {
Wayne Roberts 0:6b3ac9c5a042 345 return 0;
Wayne Roberts 0:6b3ac9c5a042 346 }
Wayne Roberts 0:6b3ac9c5a042 347
Wayne Roberts 0:6b3ac9c5a042 348 for( i = 0; i < length; i++ )
Wayne Roberts 0:6b3ac9c5a042 349 {
Wayne Roberts 0:6b3ac9c5a042 350 switch( cmdBufIn[i] )
Wayne Roberts 0:6b3ac9c5a042 351 {
Wayne Roberts 0:6b3ac9c5a042 352 // STICKY
Wayne Roberts 0:6b3ac9c5a042 353 case MOTE_MAC_RX_PARAM_SETUP_ANS:
Wayne Roberts 0:6b3ac9c5a042 354 {
Wayne Roberts 0:6b3ac9c5a042 355 cmdBufOut[cmdCount++] = cmdBufIn[i++];
Wayne Roberts 0:6b3ac9c5a042 356 cmdBufOut[cmdCount++] = cmdBufIn[i];
Wayne Roberts 0:6b3ac9c5a042 357 break;
Wayne Roberts 0:6b3ac9c5a042 358 }
Wayne Roberts 0:6b3ac9c5a042 359 case MOTE_MAC_RX_TIMING_SETUP_ANS:
Wayne Roberts 0:6b3ac9c5a042 360 {
Wayne Roberts 0:6b3ac9c5a042 361 cmdBufOut[cmdCount++] = cmdBufIn[i];
Wayne Roberts 0:6b3ac9c5a042 362 break;
Wayne Roberts 0:6b3ac9c5a042 363 }
Wayne Roberts 0:6b3ac9c5a042 364 // NON-STICKY
Wayne Roberts 0:6b3ac9c5a042 365 case MOTE_MAC_DEV_STATUS_ANS:
Wayne Roberts 0:6b3ac9c5a042 366 { // 2 bytes payload
Wayne Roberts 0:6b3ac9c5a042 367 i += 2;
Wayne Roberts 0:6b3ac9c5a042 368 break;
Wayne Roberts 0:6b3ac9c5a042 369 }
Wayne Roberts 7:4b6f960dcca2 370 case MOTE_MAC_MODE_IND:
Wayne Roberts 0:6b3ac9c5a042 371 case MOTE_MAC_LINK_ADR_ANS:
Wayne Roberts 0:6b3ac9c5a042 372 case MOTE_MAC_NEW_CHANNEL_ANS:
Wayne Roberts 0:6b3ac9c5a042 373 { // 1 byte payload
Wayne Roberts 0:6b3ac9c5a042 374 i++;
Wayne Roberts 0:6b3ac9c5a042 375 break;
Wayne Roberts 0:6b3ac9c5a042 376 }
Wayne Roberts 3:eb174e10afbb 377 case SRV_MAC_ADR_PARAM_SETUP_ANS:
Wayne Roberts 0:6b3ac9c5a042 378 case MOTE_MAC_DUTY_CYCLE_ANS:
Wayne Roberts 0:6b3ac9c5a042 379 case MOTE_MAC_LINK_CHECK_REQ:
Wayne Roberts 0:6b3ac9c5a042 380 { // 0 byte payload
Wayne Roberts 0:6b3ac9c5a042 381 break;
Wayne Roberts 0:6b3ac9c5a042 382 }
Wayne Roberts 0:6b3ac9c5a042 383 default:
Wayne Roberts 0:6b3ac9c5a042 384 break;
Wayne Roberts 0:6b3ac9c5a042 385 }
Wayne Roberts 0:6b3ac9c5a042 386 }
Wayne Roberts 0:6b3ac9c5a042 387
Wayne Roberts 0:6b3ac9c5a042 388 return cmdCount;
Wayne Roberts 7:4b6f960dcca2 389 } // ..ParseMacCommandsToRepeat()
Wayne Roberts 0:6b3ac9c5a042 390
Wayne Roberts 0:6b3ac9c5a042 391 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
Wayne Roberts 0:6b3ac9c5a042 392 {
Wayne Roberts 0:6b3ac9c5a042 393 uint32_t fcnt_up;
Wayne Roberts 0:6b3ac9c5a042 394 uint16_t i;
Wayne Roberts 0:6b3ac9c5a042 395 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 396 uint32_t mic = 0;
Wayne Roberts 0:6b3ac9c5a042 397 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 398 const void* payload = fBuffer;
Wayne Roberts 0:6b3ac9c5a042 399 uint8_t framePort = fPort;
Wayne Roberts 0:6b3ac9c5a042 400 uint8_t LoRaMacTxPayloadLen = 0;
Wayne Roberts 0:6b3ac9c5a042 401
Wayne Roberts 0:6b3ac9c5a042 402 tx_buf_len = 0;
Wayne Roberts 0:6b3ac9c5a042 403
Wayne Roberts 0:6b3ac9c5a042 404 if( fBuffer == NULL )
Wayne Roberts 0:6b3ac9c5a042 405 {
Wayne Roberts 0:6b3ac9c5a042 406 fBufferSize = 0;
Wayne Roberts 0:6b3ac9c5a042 407 }
Wayne Roberts 0:6b3ac9c5a042 408
Wayne Roberts 0:6b3ac9c5a042 409 LoRaMacTxPayloadLen = fBufferSize;
Wayne Roberts 0:6b3ac9c5a042 410
Wayne Roberts 0:6b3ac9c5a042 411 Radio::radio.tx_buf[tx_buf_len++] = macHdr->Value;
Wayne Roberts 0:6b3ac9c5a042 412
Wayne Roberts 0:6b3ac9c5a042 413 switch( macHdr->Bits.MType )
Wayne Roberts 0:6b3ac9c5a042 414 {
Wayne Roberts 0:6b3ac9c5a042 415 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 416 case FRAME_TYPE_JOIN_REQ:
Wayne Roberts 0:6b3ac9c5a042 417 if (LoRaMacJoinEui == NULL || LoRaMacDevEui == NULL)
Wayne Roberts 0:6b3ac9c5a042 418 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 419
Wayne Roberts 0:6b3ac9c5a042 420 RxWindow1Delay_us = LoRaMacParams.JoinAcceptDelay1_us - RADIO_WAKEUP_TIME_us;
Wayne Roberts 0:6b3ac9c5a042 421 RxWindow2Delay_us = LoRaMacParams.JoinAcceptDelay2_us - RADIO_WAKEUP_TIME_us;
Wayne Roberts 0:6b3ac9c5a042 422
Wayne Roberts 0:6b3ac9c5a042 423 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacJoinEui, 8 );
Wayne Roberts 0:6b3ac9c5a042 424 tx_buf_len += 8;
Wayne Roberts 0:6b3ac9c5a042 425 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
Wayne Roberts 0:6b3ac9c5a042 426 tx_buf_len += 8;
Wayne Roberts 0:6b3ac9c5a042 427
Wayne Roberts 0:6b3ac9c5a042 428 if (RootAppKey == NULL)
Wayne Roberts 0:6b3ac9c5a042 429 LoRaMacDevNonce = Radio::Random(); /* lorawan 1.0 */
Wayne Roberts 0:6b3ac9c5a042 430 else {
Wayne Roberts 0:6b3ac9c5a042 431 LoRaMacDevNonce = eeprom_read(EEPROM_DEVNONCE);
Wayne Roberts 0:6b3ac9c5a042 432 /* joinReq DevNonce value is never re-used in 1v1 */
Wayne Roberts 0:6b3ac9c5a042 433 if (eeprom_increment_value(EEPROM_DEVNONCE) < 0)
Wayne Roberts 0:6b3ac9c5a042 434 return LORAMAC_STATUS_EEPROM_FAIL;
Wayne Roberts 0:6b3ac9c5a042 435 }
Wayne Roberts 0:6b3ac9c5a042 436 MAC_PRINTF("DevNonce:%u ", LoRaMacDevNonce);
Wayne Roberts 0:6b3ac9c5a042 437
Wayne Roberts 0:6b3ac9c5a042 438 Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 439 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 440
Wayne Roberts 0:6b3ac9c5a042 441 if (LoRaMacJoinComputeMic(false, Radio::radio.tx_buf, tx_buf_len & 0xFF, RootNwkKey, &mic) < 0)
Wayne Roberts 0:6b3ac9c5a042 442 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 443
Wayne Roberts 0:6b3ac9c5a042 444 Radio::radio.tx_buf[tx_buf_len++] = mic & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 445 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 446 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 16 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 447 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 24 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 448
Wayne Roberts 0:6b3ac9c5a042 449 break;
Wayne Roberts 0:6b3ac9c5a042 450 case FRAME_TYPE_REJOIN_REQ:
Wayne Roberts 0:6b3ac9c5a042 451 RxWindow1Delay_us = LoRaMacParams.JoinAcceptDelay1_us - RADIO_WAKEUP_TIME_us;
Wayne Roberts 0:6b3ac9c5a042 452 RxWindow2Delay_us = LoRaMacParams.JoinAcceptDelay2_us - RADIO_WAKEUP_TIME_us;
Wayne Roberts 0:6b3ac9c5a042 453
Wayne Roberts 0:6b3ac9c5a042 454 Radio::radio.tx_buf[tx_buf_len++] = JoinReqType;
Wayne Roberts 0:6b3ac9c5a042 455
Wayne Roberts 0:6b3ac9c5a042 456 tx_buf_len = tx_buf_len;
Wayne Roberts 0:6b3ac9c5a042 457
Wayne Roberts 0:6b3ac9c5a042 458 if (JoinReqType == 0 || JoinReqType == 2) {
Wayne Roberts 0:6b3ac9c5a042 459 LoRaMacDevNonce = RJcount0++;
Wayne Roberts 0:6b3ac9c5a042 460 /* NetID + DevEUI */
Wayne Roberts 0:6b3ac9c5a042 461 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacNetID ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 462 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacNetID >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 463 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacNetID >> 16 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 464
Wayne Roberts 0:6b3ac9c5a042 465 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
Wayne Roberts 0:6b3ac9c5a042 466 tx_buf_len += 8;
Wayne Roberts 0:6b3ac9c5a042 467
Wayne Roberts 0:6b3ac9c5a042 468 Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 469 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 470
Wayne Roberts 0:6b3ac9c5a042 471 if (LoRaMacJoinComputeMic(false, Radio::radio.tx_buf, tx_buf_len & 0xFF, keys.SNwkSIntKey, &mic) < 0)
Wayne Roberts 0:6b3ac9c5a042 472 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 473
Wayne Roberts 0:6b3ac9c5a042 474 } else if (JoinReqType == 1) {
Wayne Roberts 0:6b3ac9c5a042 475 /* JoinEUI + DevEUI */
Wayne Roberts 0:6b3ac9c5a042 476 LoRaMacDevNonce = eeprom_read(EEPROM_RJCOUNT1);
Wayne Roberts 0:6b3ac9c5a042 477 if (eeprom_increment_value(EEPROM_RJCOUNT1) < 0)
Wayne Roberts 0:6b3ac9c5a042 478 return LORAMAC_STATUS_EEPROM_FAIL;
Wayne Roberts 0:6b3ac9c5a042 479
Wayne Roberts 0:6b3ac9c5a042 480 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacJoinEui, 8 );
Wayne Roberts 0:6b3ac9c5a042 481 tx_buf_len += 8;
Wayne Roberts 0:6b3ac9c5a042 482 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
Wayne Roberts 0:6b3ac9c5a042 483 tx_buf_len += 8;
Wayne Roberts 0:6b3ac9c5a042 484
Wayne Roberts 0:6b3ac9c5a042 485 Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 486 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 487
Wayne Roberts 0:6b3ac9c5a042 488 //print_buf(JSIntKey, 16, "JSIntKey");
Wayne Roberts 0:6b3ac9c5a042 489 if (LoRaMacJoinComputeMic(false, Radio::radio.tx_buf, tx_buf_len & 0xFF, JSIntKey, &mic) < 0)
Wayne Roberts 0:6b3ac9c5a042 490 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 491
Wayne Roberts 0:6b3ac9c5a042 492 }
Wayne Roberts 0:6b3ac9c5a042 493
Wayne Roberts 0:6b3ac9c5a042 494 Radio::radio.tx_buf[tx_buf_len++] = mic & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 495 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 496 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 16 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 497 Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 24 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 498 MAC_PRINTF("up-rejoin-frame len%u type%u\r\n", tx_buf_len, JoinReqType);
Wayne Roberts 0:6b3ac9c5a042 499 break;
Wayne Roberts 0:6b3ac9c5a042 500 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 501 case FRAME_TYPE_DATA_CONFIRMED_UP:
Wayne Roberts 0:6b3ac9c5a042 502 //Intentional fallthrough
Wayne Roberts 0:6b3ac9c5a042 503 case FRAME_TYPE_DATA_UNCONFIRMED_UP:
Wayne Roberts 0:6b3ac9c5a042 504 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 505 if (!flags.IsLoRaMacNetworkJoined)
Wayne Roberts 0:6b3ac9c5a042 506 {
Wayne Roberts 0:6b3ac9c5a042 507 return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet
Wayne Roberts 0:6b3ac9c5a042 508 }
Wayne Roberts 0:6b3ac9c5a042 509
Wayne Roberts 0:6b3ac9c5a042 510 if (flags.OptNeg && flags.need_ReKeyConf) {
Wayne Roberts 0:6b3ac9c5a042 511 /* lorawan1v1 need rekeying confirmation */
Wayne Roberts 0:6b3ac9c5a042 512 LoRaMacStatus_t s = AddMacCommand(MOTE_MAC_REKEY_IND, 0, 0);
Wayne Roberts 0:6b3ac9c5a042 513 if (s != LORAMAC_STATUS_OK)
Wayne Roberts 0:6b3ac9c5a042 514 return s;
Wayne Roberts 3:eb174e10afbb 515 if (McpsIndication.ADR_ACK_CNT > ADR_ACK_DELAY) {
Wayne Roberts 3:eb174e10afbb 516 /* give up sending rekey indication, try joining again */
Wayne Roberts 3:eb174e10afbb 517 flags.IsLoRaMacNetworkJoined = false;
Wayne Roberts 3:eb174e10afbb 518 return LORAMAC_STATUS_NO_NETWORK_JOINED;
Wayne Roberts 3:eb174e10afbb 519 }
Wayne Roberts 0:6b3ac9c5a042 520 }
Wayne Roberts 0:6b3ac9c5a042 521 fcnt_up = FCntUp;
Wayne Roberts 0:6b3ac9c5a042 522 #else
Wayne Roberts 0:6b3ac9c5a042 523 if (flags.need_ResetConf) {
Wayne Roberts 0:6b3ac9c5a042 524 LoRaMacStatus_t s = AddMacCommand(MOTE_MAC_RESET_IND, flags.OptNeg, 0);
Wayne Roberts 0:6b3ac9c5a042 525 if (s != LORAMAC_STATUS_OK)
Wayne Roberts 0:6b3ac9c5a042 526 return s;
Wayne Roberts 0:6b3ac9c5a042 527 }
Wayne Roberts 0:6b3ac9c5a042 528 fcnt_up = eeprom_read(EEPROM_FCNTUP);
Wayne Roberts 0:6b3ac9c5a042 529 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 530
Wayne Roberts 0:6b3ac9c5a042 531
Wayne Roberts 0:6b3ac9c5a042 532 if( ValidatePayloadLength( LoRaMacTxPayloadLen, LoRaMacParams.ChannelsDatarate, MacCommandsBufferIndex ) == false )
Wayne Roberts 0:6b3ac9c5a042 533 {
Wayne Roberts 0:6b3ac9c5a042 534 MAC_PRINTF("LoRaMacTxPayloadLen%u, FOptsLen%u\r\n", LoRaMacTxPayloadLen, MacCommandsBufferIndex);
Wayne Roberts 0:6b3ac9c5a042 535 return LORAMAC_STATUS_LENGTH_ERROR;
Wayne Roberts 0:6b3ac9c5a042 536 }
Wayne Roberts 0:6b3ac9c5a042 537
Wayne Roberts 0:6b3ac9c5a042 538 RxWindow1Delay_us = LoRaMacParams.ReceiveDelay1_us - RADIO_WAKEUP_TIME_us;
Wayne Roberts 0:6b3ac9c5a042 539 RxWindow2Delay_us = LoRaMacParams.ReceiveDelay2_us - RADIO_WAKEUP_TIME_us;
Wayne Roberts 0:6b3ac9c5a042 540
Wayne Roberts 0:6b3ac9c5a042 541 if( flags.SrvAckRequested == true )
Wayne Roberts 0:6b3ac9c5a042 542 {
Wayne Roberts 0:6b3ac9c5a042 543 flags.SrvAckRequested = false;
Wayne Roberts 0:6b3ac9c5a042 544 fCtrl->Bits.Ack = 1;
Wayne Roberts 0:6b3ac9c5a042 545 }
Wayne Roberts 0:6b3ac9c5a042 546
Wayne Roberts 0:6b3ac9c5a042 547 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 548 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 549 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 550 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 551
Wayne Roberts 0:6b3ac9c5a042 552 Radio::radio.tx_buf[tx_buf_len++] = fCtrl->Value;
Wayne Roberts 0:6b3ac9c5a042 553
Wayne Roberts 0:6b3ac9c5a042 554 // FCntUp will be inserted in SendFrameOnChannel(), where MIC is inserted also
Wayne Roberts 0:6b3ac9c5a042 555 tx_buf_len += 2;
Wayne Roberts 0:6b3ac9c5a042 556
Wayne Roberts 0:6b3ac9c5a042 557 ConfFCntUp = 0;
Wayne Roberts 0:6b3ac9c5a042 558 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 559 if (macHdr->Bits.MType == FRAME_TYPE_DATA_CONFIRMED_UP) {
Wayne Roberts 0:6b3ac9c5a042 560 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 561 ConfFCntUp = FCntUp;
Wayne Roberts 0:6b3ac9c5a042 562 #else
Wayne Roberts 0:6b3ac9c5a042 563 ConfFCntUp = eeprom_read(EEPROM_FCNTUP);
Wayne Roberts 0:6b3ac9c5a042 564 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 565 }
Wayne Roberts 0:6b3ac9c5a042 566 }
Wayne Roberts 0:6b3ac9c5a042 567
Wayne Roberts 0:6b3ac9c5a042 568 // Copy the MAC commands which must be re-send into the MAC command buffer
Wayne Roberts 0:6b3ac9c5a042 569 memcpy( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex );
Wayne Roberts 0:6b3ac9c5a042 570 MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex;
Wayne Roberts 0:6b3ac9c5a042 571
Wayne Roberts 0:6b3ac9c5a042 572 if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
Wayne Roberts 0:6b3ac9c5a042 573 {
Wayne Roberts 0:6b3ac9c5a042 574 if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( flags.MacCommandsInNextTx == true ) )
Wayne Roberts 0:6b3ac9c5a042 575 {
Wayne Roberts 0:6b3ac9c5a042 576 MAC_PRINTF("uplink mac-cmds %u into FOpts at %u ", MacCommandsBufferIndex, tx_buf_len);
Wayne Roberts 0:6b3ac9c5a042 577 fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
Wayne Roberts 0:6b3ac9c5a042 578 // Update FCtrl field with new value of OptionsLength
Wayne Roberts 0:6b3ac9c5a042 579 Radio::radio.tx_buf[0x05] = fCtrl->Value;
Wayne Roberts 0:6b3ac9c5a042 580
Wayne Roberts 0:6b3ac9c5a042 581 /* lorawan1v1: encode FOpts using NWkSEncKey */
Wayne Roberts 0:6b3ac9c5a042 582 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 583 LoRaMacEncrypt(0, MacCommandsBuffer, MacCommandsBufferIndex, keys.NwkSEncKey, LoRaMacDevAddr, UP_LINK, fcnt_up, Radio::radio.tx_buf + tx_buf_len);
Wayne Roberts 0:6b3ac9c5a042 584 tx_buf_len += MacCommandsBufferIndex;
Wayne Roberts 0:6b3ac9c5a042 585 } else {
Wayne Roberts 0:6b3ac9c5a042 586 for( i = 0; i < MacCommandsBufferIndex; i++ )
Wayne Roberts 0:6b3ac9c5a042 587 {
Wayne Roberts 0:6b3ac9c5a042 588 Radio::radio.tx_buf[tx_buf_len++] = MacCommandsBuffer[i];
Wayne Roberts 0:6b3ac9c5a042 589 MAC_PRINTF("%02x ", MacCommandsBuffer[i]);
Wayne Roberts 0:6b3ac9c5a042 590 }
Wayne Roberts 0:6b3ac9c5a042 591 MAC_PRINTF(" fCtrl->Value:%02x\r\n", Radio::radio.tx_buf[0x05]);
Wayne Roberts 0:6b3ac9c5a042 592 }
Wayne Roberts 0:6b3ac9c5a042 593 }
Wayne Roberts 0:6b3ac9c5a042 594 }
Wayne Roberts 0:6b3ac9c5a042 595 else
Wayne Roberts 0:6b3ac9c5a042 596 {
Wayne Roberts 0:6b3ac9c5a042 597 if( ( MacCommandsBufferIndex > 0 ) && ( flags.MacCommandsInNextTx ) )
Wayne Roberts 0:6b3ac9c5a042 598 {
Wayne Roberts 0:6b3ac9c5a042 599 MAC_PRINTF("uplink mac-cmds %u port0 ", MacCommandsBufferIndex);
Wayne Roberts 0:6b3ac9c5a042 600 for (i = 0; i < MacCommandsBufferIndex; i++)
Wayne Roberts 0:6b3ac9c5a042 601 MAC_PRINTF("%02x ", MacCommandsBuffer[i]);
Wayne Roberts 0:6b3ac9c5a042 602 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 603 LoRaMacTxPayloadLen = MacCommandsBufferIndex;
Wayne Roberts 0:6b3ac9c5a042 604 payload = MacCommandsBuffer;
Wayne Roberts 0:6b3ac9c5a042 605 framePort = 0;
Wayne Roberts 0:6b3ac9c5a042 606 }
Wayne Roberts 0:6b3ac9c5a042 607 }
Wayne Roberts 0:6b3ac9c5a042 608 flags.MacCommandsInNextTx = false;
Wayne Roberts 0:6b3ac9c5a042 609 // Store MAC commands which must be re-send in case the device does not receive a downlink anymore
Wayne Roberts 0:6b3ac9c5a042 610 MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat( MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat );
Wayne Roberts 0:6b3ac9c5a042 611 if( MacCommandsBufferToRepeatIndex > 0 )
Wayne Roberts 0:6b3ac9c5a042 612 {
Wayne Roberts 0:6b3ac9c5a042 613 flags.MacCommandsInNextTx = true;
Wayne Roberts 0:6b3ac9c5a042 614 }
Wayne Roberts 0:6b3ac9c5a042 615 MacCommandsBufferIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 616
Wayne Roberts 0:6b3ac9c5a042 617 if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
Wayne Roberts 0:6b3ac9c5a042 618 {
Wayne Roberts 0:6b3ac9c5a042 619 const uint8_t* keyPtr;
Wayne Roberts 0:6b3ac9c5a042 620 Radio::radio.tx_buf[tx_buf_len++] = framePort;
Wayne Roberts 0:6b3ac9c5a042 621
Wayne Roberts 0:6b3ac9c5a042 622 if( framePort == 0 )
Wayne Roberts 0:6b3ac9c5a042 623 {
Wayne Roberts 0:6b3ac9c5a042 624 DEBUG_CRYPT_BUF(keys.NwkSEncKey, 16, "NwkSEncKey", 0);
Wayne Roberts 0:6b3ac9c5a042 625 keyPtr = keys.NwkSEncKey;
Wayne Roberts 0:6b3ac9c5a042 626 }
Wayne Roberts 0:6b3ac9c5a042 627 else
Wayne Roberts 0:6b3ac9c5a042 628 {
Wayne Roberts 0:6b3ac9c5a042 629 DEBUG_CRYPT_BUF(keys.AppSKey, 16, "AppSKey", 0);
Wayne Roberts 0:6b3ac9c5a042 630 keyPtr = keys.AppSKey;
Wayne Roberts 0:6b3ac9c5a042 631 }
Wayne Roberts 0:6b3ac9c5a042 632 LoRaMacEncrypt(1, (uint8_t* ) payload, LoRaMacTxPayloadLen, keyPtr, LoRaMacDevAddr, UP_LINK, fcnt_up, Radio::radio.tx_buf + tx_buf_len);
Wayne Roberts 0:6b3ac9c5a042 633 }
Wayne Roberts 0:6b3ac9c5a042 634 tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
Wayne Roberts 0:6b3ac9c5a042 635 /* mic cacluation in SendFrameOnChannel() */
Wayne Roberts 0:6b3ac9c5a042 636 break;
Wayne Roberts 0:6b3ac9c5a042 637 case FRAME_TYPE_PROPRIETARY:
Wayne Roberts 0:6b3ac9c5a042 638 if( ( fBuffer != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
Wayne Roberts 0:6b3ac9c5a042 639 {
Wayne Roberts 0:6b3ac9c5a042 640 memcpy( Radio::radio.tx_buf + tx_buf_len, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen );
Wayne Roberts 0:6b3ac9c5a042 641 tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
Wayne Roberts 0:6b3ac9c5a042 642 }
Wayne Roberts 0:6b3ac9c5a042 643 break;
Wayne Roberts 0:6b3ac9c5a042 644 default:
Wayne Roberts 0:6b3ac9c5a042 645 return LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 646 }
Wayne Roberts 0:6b3ac9c5a042 647
Wayne Roberts 0:6b3ac9c5a042 648 flags.uplink_mtype = macHdr->Bits.MType;
Wayne Roberts 0:6b3ac9c5a042 649 flags.uplink_in_progress = LoRaMacParams.NbTrans;
Wayne Roberts 0:6b3ac9c5a042 650
Wayne Roberts 0:6b3ac9c5a042 651 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 652 } // ..PrepareFrame()
Wayne Roberts 0:6b3ac9c5a042 653
Wayne Roberts 0:6b3ac9c5a042 654 LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
Wayne Roberts 0:6b3ac9c5a042 655 {
Wayne Roberts 0:6b3ac9c5a042 656 LoRaMacFrameCtrl_t fCtrl;
Wayne Roberts 0:6b3ac9c5a042 657 LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 658
Wayne Roberts 0:6b3ac9c5a042 659 fCtrl.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 660 fCtrl.Bits.FOptsLen = 0;
Wayne Roberts 0:6b3ac9c5a042 661 if( LoRaMacDeviceClass == CLASS_B )
Wayne Roberts 0:6b3ac9c5a042 662 {
Wayne Roberts 0:6b3ac9c5a042 663 fCtrl.Bits.FPending = 1;
Wayne Roberts 0:6b3ac9c5a042 664 }
Wayne Roberts 0:6b3ac9c5a042 665 else
Wayne Roberts 0:6b3ac9c5a042 666 {
Wayne Roberts 0:6b3ac9c5a042 667 fCtrl.Bits.FPending = 0;
Wayne Roberts 0:6b3ac9c5a042 668 }
Wayne Roberts 0:6b3ac9c5a042 669 fCtrl.Bits.Ack = false;
Wayne Roberts 0:6b3ac9c5a042 670 fCtrl.Bits.AdrAckReq = false;
Wayne Roberts 0:6b3ac9c5a042 671 fCtrl.Bits.Adr = flags.AdrCtrlOn;
Wayne Roberts 0:6b3ac9c5a042 672
Wayne Roberts 0:6b3ac9c5a042 673 // Prepare the frame
Wayne Roberts 0:6b3ac9c5a042 674 status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
Wayne Roberts 0:6b3ac9c5a042 675
Wayne Roberts 0:6b3ac9c5a042 676 // Validate status
Wayne Roberts 0:6b3ac9c5a042 677 if( status != LORAMAC_STATUS_OK )
Wayne Roberts 0:6b3ac9c5a042 678 {
Wayne Roberts 0:6b3ac9c5a042 679 return status;
Wayne Roberts 0:6b3ac9c5a042 680 }
Wayne Roberts 0:6b3ac9c5a042 681
Wayne Roberts 0:6b3ac9c5a042 682 // Reset confirm parameters
Wayne Roberts 0:6b3ac9c5a042 683 McpsConfirm.NbRetries = 0;
Wayne Roberts 0:6b3ac9c5a042 684 McpsConfirm.AckReceived = false;
Wayne Roberts 0:6b3ac9c5a042 685
Wayne Roberts 0:6b3ac9c5a042 686 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 687 if (flags.rxing)
Wayne Roberts 0:6b3ac9c5a042 688 function_pending = region_ScheduleTx;
Wayne Roberts 0:6b3ac9c5a042 689 else
Wayne Roberts 0:6b3ac9c5a042 690 region_ScheduleTx( );
Wayne Roberts 0:6b3ac9c5a042 691
Wayne Roberts 0:6b3ac9c5a042 692 return status;
Wayne Roberts 0:6b3ac9c5a042 693 } // ..Send()
Wayne Roberts 0:6b3ac9c5a042 694
Wayne Roberts 5:4e9d41359897 695 LoRaMacStatus_t waitingFor;
Wayne Roberts 5:4e9d41359897 696
Wayne Roberts 0:6b3ac9c5a042 697 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 698 LoRaMacMlmeRequest( const MlmeReq_t *mlmeRequest )
Wayne Roberts 0:6b3ac9c5a042 699 {
Wayne Roberts 0:6b3ac9c5a042 700 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 701 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 702 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 703 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 704
Wayne Roberts 0:6b3ac9c5a042 705 if( mlmeRequest == NULL )
Wayne Roberts 0:6b3ac9c5a042 706 {
Wayne Roberts 0:6b3ac9c5a042 707 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 708 }
Wayne Roberts 0:6b3ac9c5a042 709
Wayne Roberts 0:6b3ac9c5a042 710 if (flags.uplink_in_progress > 0) {
Wayne Roberts 0:6b3ac9c5a042 711 MAC_PRINTF("LoRaMacMlmeRequest() BUSY\r\n");
Wayne Roberts 5:4e9d41359897 712 return waitingFor;
Wayne Roberts 0:6b3ac9c5a042 713 }
Wayne Roberts 0:6b3ac9c5a042 714
Wayne Roberts 0:6b3ac9c5a042 715 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_MLMEREQ;
Wayne Roberts 0:6b3ac9c5a042 716 MlmeIndication.MlmeIndication = mlmeRequest->Type;
Wayne Roberts 0:6b3ac9c5a042 717
Wayne Roberts 5:4e9d41359897 718 waitingFor = LORAMAC_STATUS_WAITING_FOR_TXSTART;
Wayne Roberts 5:4e9d41359897 719
Wayne Roberts 0:6b3ac9c5a042 720 MAC_PRINTF("LoRaMacMlmeRequest() ");
Wayne Roberts 0:6b3ac9c5a042 721 switch( mlmeRequest->Type )
Wayne Roberts 0:6b3ac9c5a042 722 {
Wayne Roberts 0:6b3ac9c5a042 723 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 724 case MLME_JOIN:
Wayne Roberts 0:6b3ac9c5a042 725 {
Wayne Roberts 0:6b3ac9c5a042 726 if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 727 ( mlmeRequest->Req.Join.JoinEui == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 728 ( mlmeRequest->Req.Join.NwkKey == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 729 ( mlmeRequest->Req.Join.NbTrials == 0 ) )
Wayne Roberts 0:6b3ac9c5a042 730 {
Wayne Roberts 0:6b3ac9c5a042 731 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 732 }
Wayne Roberts 0:6b3ac9c5a042 733
Wayne Roberts 0:6b3ac9c5a042 734 LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
Wayne Roberts 0:6b3ac9c5a042 735 LoRaMacJoinEui = mlmeRequest->Req.Join.JoinEui;
Wayne Roberts 0:6b3ac9c5a042 736 RootNwkKey = mlmeRequest->Req.Join.NwkKey;
Wayne Roberts 0:6b3ac9c5a042 737 RootAppKey = mlmeRequest->Req.Join.AppKey;
Wayne Roberts 0:6b3ac9c5a042 738 MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials;
Wayne Roberts 0:6b3ac9c5a042 739
Wayne Roberts 0:6b3ac9c5a042 740 /*if (RootAppKey != NULL) {*/
Wayne Roberts 0:6b3ac9c5a042 741 LoRaMacGenerateJoinKey(0x05, RootNwkKey, LoRaMacDevEui, JSEncKey);
Wayne Roberts 0:6b3ac9c5a042 742 //print_buf(JSEncKey, 16, "new-JSEncKey");
Wayne Roberts 0:6b3ac9c5a042 743 LoRaMacGenerateJoinKey(0x06, RootNwkKey, LoRaMacDevEui, JSIntKey);
Wayne Roberts 0:6b3ac9c5a042 744 //print_buf(JSIntKey, 16, "new-JSIntKey");
Wayne Roberts 0:6b3ac9c5a042 745 /*}*/
Wayne Roberts 0:6b3ac9c5a042 746 JoinReqType = 0xff;
Wayne Roberts 0:6b3ac9c5a042 747
Wayne Roberts 0:6b3ac9c5a042 748 // Reset variable JoinRequestTrials
Wayne Roberts 0:6b3ac9c5a042 749 MlmeIndication.JoinRequestTrials = 0;
Wayne Roberts 0:6b3ac9c5a042 750
Wayne Roberts 0:6b3ac9c5a042 751 // Setup header information
Wayne Roberts 0:6b3ac9c5a042 752 macHdr.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 753 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
Wayne Roberts 0:6b3ac9c5a042 754
Wayne Roberts 0:6b3ac9c5a042 755 ResetMacParameters( );
Wayne Roberts 0:6b3ac9c5a042 756
Wayne Roberts 0:6b3ac9c5a042 757 // Add a +1, since we start to count from 0
Wayne Roberts 3:eb174e10afbb 758 LoRaMacParams.ChannelsDatarate = region_AlternateDatarate( MlmeIndication.JoinRequestTrials + 1 );
Wayne Roberts 0:6b3ac9c5a042 759
Wayne Roberts 0:6b3ac9c5a042 760 status = Send( &macHdr, 0, NULL, 0 );
Wayne Roberts 0:6b3ac9c5a042 761 break;
Wayne Roberts 0:6b3ac9c5a042 762 }
Wayne Roberts 0:6b3ac9c5a042 763 case MLME_REJOIN_1:
Wayne Roberts 0:6b3ac9c5a042 764 if ( mlmeRequest->Req.Join.JoinEui == NULL )
Wayne Roberts 0:6b3ac9c5a042 765 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 766
Wayne Roberts 0:6b3ac9c5a042 767 LoRaMacJoinEui = mlmeRequest->Req.Join.JoinEui;
Wayne Roberts 0:6b3ac9c5a042 768 JoinReqType = 0x01;
Wayne Roberts 0:6b3ac9c5a042 769 // fall-thru
Wayne Roberts 0:6b3ac9c5a042 770 case MLME_REJOIN_0:
Wayne Roberts 0:6b3ac9c5a042 771 case MLME_REJOIN_2: // Type2 can only be sent via mac-command
Wayne Roberts 0:6b3ac9c5a042 772 if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 773 ( mlmeRequest->Req.Join.NwkKey == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 774 ( mlmeRequest->Req.Join.NbTrials == 0 ) )
Wayne Roberts 0:6b3ac9c5a042 775 {
Wayne Roberts 0:6b3ac9c5a042 776 MAC_PRINTF(" (missing %p %p %d)\n",
Wayne Roberts 0:6b3ac9c5a042 777 mlmeRequest->Req.Join.DevEui,
Wayne Roberts 0:6b3ac9c5a042 778 mlmeRequest->Req.Join.NwkKey,
Wayne Roberts 0:6b3ac9c5a042 779 mlmeRequest->Req.Join.NbTrials
Wayne Roberts 0:6b3ac9c5a042 780 );
Wayne Roberts 0:6b3ac9c5a042 781 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 782 }
Wayne Roberts 0:6b3ac9c5a042 783
Wayne Roberts 0:6b3ac9c5a042 784 RootNwkKey = mlmeRequest->Req.Join.NwkKey;
Wayne Roberts 0:6b3ac9c5a042 785 LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
Wayne Roberts 0:6b3ac9c5a042 786 LoRaMacGenerateJoinKey(0x05, RootNwkKey, LoRaMacDevEui, JSEncKey);
Wayne Roberts 0:6b3ac9c5a042 787 LoRaMacGenerateJoinKey(0x06, RootNwkKey, LoRaMacDevEui, JSIntKey);
Wayne Roberts 0:6b3ac9c5a042 788
Wayne Roberts 0:6b3ac9c5a042 789 RootAppKey = mlmeRequest->Req.Join.AppKey;
Wayne Roberts 0:6b3ac9c5a042 790
Wayne Roberts 0:6b3ac9c5a042 791 macHdr.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 792 macHdr.Bits.MType = FRAME_TYPE_REJOIN_REQ;
Wayne Roberts 0:6b3ac9c5a042 793
Wayne Roberts 0:6b3ac9c5a042 794 if (mlmeRequest->Type == MLME_REJOIN_0)
Wayne Roberts 0:6b3ac9c5a042 795 JoinReqType = 0x00;
Wayne Roberts 0:6b3ac9c5a042 796 else if (mlmeRequest->Type == MLME_REJOIN_2)
Wayne Roberts 0:6b3ac9c5a042 797 JoinReqType = 0x02;
Wayne Roberts 0:6b3ac9c5a042 798
Wayne Roberts 0:6b3ac9c5a042 799 MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials;
Wayne Roberts 0:6b3ac9c5a042 800
Wayne Roberts 0:6b3ac9c5a042 801 status = Send( &macHdr, 0, NULL, 0 );
Wayne Roberts 0:6b3ac9c5a042 802 break;
Wayne Roberts 0:6b3ac9c5a042 803 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 804 case MLME_LINK_CHECK:
Wayne Roberts 0:6b3ac9c5a042 805 status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
Wayne Roberts 0:6b3ac9c5a042 806 break;
Wayne Roberts 0:6b3ac9c5a042 807 case MLME_TIME_REQ:
Wayne Roberts 0:6b3ac9c5a042 808 status = AddMacCommand( MOTE_MAC_DEVICE_TIME_REQ, 0, 0 );
Wayne Roberts 0:6b3ac9c5a042 809 break;
Wayne Roberts 0:6b3ac9c5a042 810 case MLME_TXCW:
Wayne Roberts 0:6b3ac9c5a042 811 status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout );
Wayne Roberts 0:6b3ac9c5a042 812 break;
Wayne Roberts 0:6b3ac9c5a042 813 case MLME_PING_SLOT_INFO:
Wayne Roberts 0:6b3ac9c5a042 814 {
Wayne Roberts 0:6b3ac9c5a042 815 uint8_t value = mlmeRequest->Req.PingSlotInfo.Value;
Wayne Roberts 0:6b3ac9c5a042 816 status = LoRaMacMlmeRequestClassB(mlmeRequest);
Wayne Roberts 0:6b3ac9c5a042 817 if (status == LORAMAC_STATUS_OK)
Wayne Roberts 0:6b3ac9c5a042 818 status = AddMacCommandClassB( MOTE_MAC_PING_SLOT_INFO_REQ, value, 0 );
Wayne Roberts 0:6b3ac9c5a042 819 break;
Wayne Roberts 0:6b3ac9c5a042 820 }
Wayne Roberts 0:6b3ac9c5a042 821 case MLME_BEACON_ACQUISITION:
Wayne Roberts 0:6b3ac9c5a042 822 case MLME_BEACON_TIMING:
Wayne Roberts 0:6b3ac9c5a042 823 status = LoRaMacMlmeRequestClassB(mlmeRequest);
Wayne Roberts 0:6b3ac9c5a042 824 break;
Wayne Roberts 0:6b3ac9c5a042 825 default:
Wayne Roberts 0:6b3ac9c5a042 826 break;
Wayne Roberts 0:6b3ac9c5a042 827 } // ...switch( mlmeRequest->Type )
Wayne Roberts 0:6b3ac9c5a042 828
Wayne Roberts 0:6b3ac9c5a042 829 if( status != LORAMAC_STATUS_OK )
Wayne Roberts 0:6b3ac9c5a042 830 MlmeConfirm.MlmeRequest = MLME_NONE;
Wayne Roberts 0:6b3ac9c5a042 831 else
Wayne Roberts 0:6b3ac9c5a042 832 {
Wayne Roberts 0:6b3ac9c5a042 833 MlmeConfirm.MlmeRequest = mlmeRequest->Type;
Wayne Roberts 0:6b3ac9c5a042 834 }
Wayne Roberts 0:6b3ac9c5a042 835
Wayne Roberts 0:6b3ac9c5a042 836 return status;
Wayne Roberts 0:6b3ac9c5a042 837 } // ..LoRaMacMlmeRequest()
Wayne Roberts 0:6b3ac9c5a042 838
Wayne Roberts 0:6b3ac9c5a042 839 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 840 LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
Wayne Roberts 0:6b3ac9c5a042 841 {
Wayne Roberts 0:6b3ac9c5a042 842 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 843
Wayne Roberts 0:6b3ac9c5a042 844 switch( mibGet->Type ) {
Wayne Roberts 0:6b3ac9c5a042 845 case MIB_APP_SKEY:
Wayne Roberts 0:6b3ac9c5a042 846 mibGet->Param.key = keys.AppSKey;
Wayne Roberts 0:6b3ac9c5a042 847 break;
Wayne Roberts 0:6b3ac9c5a042 848 case MIB_FNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 849 mibGet->Param.key = keys.FNwkSIntKey;
Wayne Roberts 0:6b3ac9c5a042 850 break;
Wayne Roberts 0:6b3ac9c5a042 851 case MIB_SNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 852 mibGet->Param.key = keys.SNwkSIntKey;
Wayne Roberts 0:6b3ac9c5a042 853 break;
Wayne Roberts 0:6b3ac9c5a042 854 case MIB_NwkSEncKey:
Wayne Roberts 0:6b3ac9c5a042 855 mibGet->Param.key = keys.NwkSEncKey;
Wayne Roberts 0:6b3ac9c5a042 856 break;
Wayne Roberts 0:6b3ac9c5a042 857 case MIB_NwkSKey:
Wayne Roberts 0:6b3ac9c5a042 858 /* lorawan 1.0 */
Wayne Roberts 0:6b3ac9c5a042 859 mibGet->Param.key = keys.FNwkSIntKey;
Wayne Roberts 0:6b3ac9c5a042 860 break;
Wayne Roberts 0:6b3ac9c5a042 861 case MIB_RX2_CHANNEL:
Wayne Roberts 0:6b3ac9c5a042 862 mibGet->Param.Rx2Channel = LoRaMacParams.Rx2Channel;
Wayne Roberts 0:6b3ac9c5a042 863 break;
Wayne Roberts 0:6b3ac9c5a042 864 case MIB_DEVICE_CLASS:
Wayne Roberts 0:6b3ac9c5a042 865 mibGet->Param.Class = LoRaMacDeviceClass;
Wayne Roberts 0:6b3ac9c5a042 866 break;
Wayne Roberts 0:6b3ac9c5a042 867 case MIB_ADR:
Wayne Roberts 0:6b3ac9c5a042 868 mibGet->Param.AdrEnable = flags.AdrCtrlOn;
Wayne Roberts 0:6b3ac9c5a042 869 break;
Wayne Roberts 0:6b3ac9c5a042 870 case MIB_DEV_ADDR:
Wayne Roberts 0:6b3ac9c5a042 871 mibGet->Param.DevAddr = LoRaMacDevAddr;
Wayne Roberts 0:6b3ac9c5a042 872 break;
Wayne Roberts 0:6b3ac9c5a042 873 case MIB_PUBLIC_NETWORK:
Wayne Roberts 0:6b3ac9c5a042 874 mibGet->Param.EnablePublicNetwork = flags.PublicNetwork;
Wayne Roberts 0:6b3ac9c5a042 875 break;
Wayne Roberts 0:6b3ac9c5a042 876 case MIB_CHANNELS_MASK:
Wayne Roberts 0:6b3ac9c5a042 877 mibGet->Param.ChannelsMask = LoRaMacParams.ChannelsMask;
Wayne Roberts 3:eb174e10afbb 878 LoRaMacParams.NbEnabledChannels = region_CountNbEnabledChannels();
Wayne Roberts 0:6b3ac9c5a042 879 break;
Wayne Roberts 7:4b6f960dcca2 880 case MIB_MAX_LISTEN_TIME:
Wayne Roberts 7:4b6f960dcca2 881 mibGet->Param.MaxListenTime = LoRaMacParams.MaxListenTime;
Wayne Roberts 7:4b6f960dcca2 882 break;
Wayne Roberts 0:6b3ac9c5a042 883 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 884 case MIB_NETWORK_JOINED:
Wayne Roberts 0:6b3ac9c5a042 885 mibGet->Param.IsNetworkJoined = flags.IsLoRaMacNetworkJoined;
Wayne Roberts 0:6b3ac9c5a042 886 break;
Wayne Roberts 0:6b3ac9c5a042 887 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 888 } // ..switch( mibGet->Type )
Wayne Roberts 0:6b3ac9c5a042 889
Wayne Roberts 0:6b3ac9c5a042 890 return status;
Wayne Roberts 0:6b3ac9c5a042 891 }
Wayne Roberts 0:6b3ac9c5a042 892
Wayne Roberts 0:6b3ac9c5a042 893
Wayne Roberts 0:6b3ac9c5a042 894 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 895 LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t* txInfo)
Wayne Roberts 0:6b3ac9c5a042 896 {
Wayne Roberts 0:6b3ac9c5a042 897 int8_t datarate = LoRaMacParamsDefaults.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 898 uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
Wayne Roberts 0:6b3ac9c5a042 899
Wayne Roberts 0:6b3ac9c5a042 900 if( txInfo == NULL )
Wayne Roberts 0:6b3ac9c5a042 901 {
Wayne Roberts 0:6b3ac9c5a042 902 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 903 }
Wayne Roberts 0:6b3ac9c5a042 904
Wayne Roberts 3:eb174e10afbb 905 //AdrNextDr( flags.AdrCtrlOn, false, &datarate );
Wayne Roberts 0:6b3ac9c5a042 906
Wayne Roberts 0:6b3ac9c5a042 907 txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate];
Wayne Roberts 0:6b3ac9c5a042 908
Wayne Roberts 0:6b3ac9c5a042 909 if( txInfo->CurrentPayloadSize >= fOptLen )
Wayne Roberts 0:6b3ac9c5a042 910 {
Wayne Roberts 0:6b3ac9c5a042 911 txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen;
Wayne Roberts 0:6b3ac9c5a042 912 }
Wayne Roberts 0:6b3ac9c5a042 913 else
Wayne Roberts 0:6b3ac9c5a042 914 {
Wayne Roberts 0:6b3ac9c5a042 915 return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
Wayne Roberts 0:6b3ac9c5a042 916 }
Wayne Roberts 0:6b3ac9c5a042 917
Wayne Roberts 0:6b3ac9c5a042 918 if( ValidatePayloadLength( size, datarate, 0 ) == false )
Wayne Roberts 0:6b3ac9c5a042 919 {
Wayne Roberts 0:6b3ac9c5a042 920 return LORAMAC_STATUS_LENGTH_ERROR;
Wayne Roberts 0:6b3ac9c5a042 921 }
Wayne Roberts 0:6b3ac9c5a042 922
Wayne Roberts 0:6b3ac9c5a042 923 if( ValidatePayloadLength( size, datarate, fOptLen ) == false )
Wayne Roberts 0:6b3ac9c5a042 924 {
Wayne Roberts 0:6b3ac9c5a042 925 return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
Wayne Roberts 0:6b3ac9c5a042 926 }
Wayne Roberts 0:6b3ac9c5a042 927
Wayne Roberts 0:6b3ac9c5a042 928 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 929 }
Wayne Roberts 0:6b3ac9c5a042 930
Wayne Roberts 0:6b3ac9c5a042 931 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 932 LoRaMacMcpsRequest( McpsReq_t *mcpsRequest )
Wayne Roberts 0:6b3ac9c5a042 933 {
Wayne Roberts 0:6b3ac9c5a042 934 LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 935 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 936 uint8_t fPort = 0;
Wayne Roberts 0:6b3ac9c5a042 937 void *fBuffer;
Wayne Roberts 0:6b3ac9c5a042 938 uint16_t fBufferSize;
Wayne Roberts 0:6b3ac9c5a042 939 int8_t datarate;
Wayne Roberts 0:6b3ac9c5a042 940 bool readyToSend = false;
Wayne Roberts 0:6b3ac9c5a042 941
Wayne Roberts 0:6b3ac9c5a042 942 if( mcpsRequest == NULL )
Wayne Roberts 0:6b3ac9c5a042 943 {
Wayne Roberts 0:6b3ac9c5a042 944 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 945 }
Wayne Roberts 0:6b3ac9c5a042 946 if (flags.uplink_in_progress > 0) {
Wayne Roberts 7:4b6f960dcca2 947 MAC_PRINTF("LoRaMacMcpsRequest() in_progress BUSY%u\r\n", flags.uplink_in_progress);
Wayne Roberts 5:4e9d41359897 948 return waitingFor;
Wayne Roberts 0:6b3ac9c5a042 949 }
Wayne Roberts 0:6b3ac9c5a042 950 if (ConfFCntUp > 0) {
Wayne Roberts 0:6b3ac9c5a042 951 // unacknowledged confirmed uplink pending, must resend previous uplink
Wayne Roberts 0:6b3ac9c5a042 952 MAC_PRINTF("LoRaMacMcpsRequest() ConfFCntUp%u\r\n", ConfFCntUp);
Wayne Roberts 0:6b3ac9c5a042 953 return LORAMAC_STATUS_BUSY_UPCONF;
Wayne Roberts 0:6b3ac9c5a042 954 }
Wayne Roberts 0:6b3ac9c5a042 955
Wayne Roberts 0:6b3ac9c5a042 956 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 957 if (!flags.IsLoRaMacNetworkJoined)
Wayne Roberts 0:6b3ac9c5a042 958 return LORAMAC_STATUS_NO_NETWORK_JOINED;
Wayne Roberts 0:6b3ac9c5a042 959 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 960
Wayne Roberts 0:6b3ac9c5a042 961 macHdr.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 962 memset ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) );
Wayne Roberts 0:6b3ac9c5a042 963 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_MCPSREQ;
Wayne Roberts 0:6b3ac9c5a042 964 McpsConfirm.McpsRequest = mcpsRequest->Type;
Wayne Roberts 0:6b3ac9c5a042 965
Wayne Roberts 0:6b3ac9c5a042 966 datarate = mcpsRequest->Req.Datarate;
Wayne Roberts 0:6b3ac9c5a042 967 fBufferSize = mcpsRequest->Req.fBufferSize;
Wayne Roberts 0:6b3ac9c5a042 968 fBuffer = mcpsRequest->Req.fBuffer;
Wayne Roberts 0:6b3ac9c5a042 969 readyToSend = true;
Wayne Roberts 0:6b3ac9c5a042 970
Wayne Roberts 0:6b3ac9c5a042 971 switch( mcpsRequest->Type )
Wayne Roberts 0:6b3ac9c5a042 972 {
Wayne Roberts 0:6b3ac9c5a042 973 case MCPS_UNCONFIRMED:
Wayne Roberts 0:6b3ac9c5a042 974 {
Wayne Roberts 0:6b3ac9c5a042 975 macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
Wayne Roberts 0:6b3ac9c5a042 976 fPort = mcpsRequest->Req.fPort;
Wayne Roberts 0:6b3ac9c5a042 977 break;
Wayne Roberts 0:6b3ac9c5a042 978 }
Wayne Roberts 0:6b3ac9c5a042 979 case MCPS_CONFIRMED:
Wayne Roberts 0:6b3ac9c5a042 980 {
Wayne Roberts 3:eb174e10afbb 981 //AckTimeoutRetriesCounter = 1;
Wayne Roberts 3:eb174e10afbb 982 //AckTimeoutRetries = mcpsRequest->Req.NbTrials;
Wayne Roberts 0:6b3ac9c5a042 983
Wayne Roberts 0:6b3ac9c5a042 984 macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
Wayne Roberts 0:6b3ac9c5a042 985 fPort = mcpsRequest->Req.fPort;
Wayne Roberts 0:6b3ac9c5a042 986 break;
Wayne Roberts 0:6b3ac9c5a042 987 }
Wayne Roberts 0:6b3ac9c5a042 988 case MCPS_PROPRIETARY:
Wayne Roberts 0:6b3ac9c5a042 989 {
Wayne Roberts 0:6b3ac9c5a042 990 macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
Wayne Roberts 0:6b3ac9c5a042 991 break;
Wayne Roberts 0:6b3ac9c5a042 992 }
Wayne Roberts 0:6b3ac9c5a042 993 default:
Wayne Roberts 0:6b3ac9c5a042 994 readyToSend = false;
Wayne Roberts 0:6b3ac9c5a042 995 break;
Wayne Roberts 0:6b3ac9c5a042 996 }
Wayne Roberts 0:6b3ac9c5a042 997
Wayne Roberts 0:6b3ac9c5a042 998 if( readyToSend == true )
Wayne Roberts 0:6b3ac9c5a042 999 {
Wayne Roberts 0:6b3ac9c5a042 1000 if( flags.AdrCtrlOn == false )
Wayne Roberts 0:6b3ac9c5a042 1001 {
Wayne Roberts 0:6b3ac9c5a042 1002 if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == true )
Wayne Roberts 0:6b3ac9c5a042 1003 {
Wayne Roberts 0:6b3ac9c5a042 1004 LoRaMacParams.ChannelsDatarate = datarate;
Wayne Roberts 0:6b3ac9c5a042 1005 }
Wayne Roberts 0:6b3ac9c5a042 1006 else
Wayne Roberts 0:6b3ac9c5a042 1007 {
Wayne Roberts 0:6b3ac9c5a042 1008 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1009 }
Wayne Roberts 0:6b3ac9c5a042 1010 }
Wayne Roberts 0:6b3ac9c5a042 1011
Wayne Roberts 0:6b3ac9c5a042 1012 status = Send( &macHdr, fPort, fBuffer, fBufferSize );
Wayne Roberts 0:6b3ac9c5a042 1013 }
Wayne Roberts 0:6b3ac9c5a042 1014
Wayne Roberts 0:6b3ac9c5a042 1015 return status;
Wayne Roberts 0:6b3ac9c5a042 1016 } // ..LoRaMacMcpsRequest()
Wayne Roberts 0:6b3ac9c5a042 1017
Wayne Roberts 0:6b3ac9c5a042 1018 __attribute__((weak)) LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 1019 SwitchClassB( DeviceClass_t deviceClass )
Wayne Roberts 0:6b3ac9c5a042 1020 {
Wayne Roberts 0:6b3ac9c5a042 1021 return LORAMAC_STATUS_DEVICE_OFF;
Wayne Roberts 0:6b3ac9c5a042 1022 }
Wayne Roberts 0:6b3ac9c5a042 1023
Wayne Roberts 0:6b3ac9c5a042 1024 void
Wayne Roberts 0:6b3ac9c5a042 1025 RxWindowSetup( unsigned freq, int8_t datarate, unsigned bandwidth, uint16_t timeout)
Wayne Roberts 0:6b3ac9c5a042 1026 {
Wayne Roberts 0:6b3ac9c5a042 1027 uint8_t downlinkDatarate = Datarates[datarate];
Wayne Roberts 0:6b3ac9c5a042 1028 RadioModems_t modem;
Wayne Roberts 0:6b3ac9c5a042 1029
Wayne Roberts 0:6b3ac9c5a042 1030 MAC_PRINTF(" rxwin-dr%u-sf%u ", datarate, downlinkDatarate);
Wayne Roberts 0:6b3ac9c5a042 1031 Radio::SetChannel( freq );
Wayne Roberts 0:6b3ac9c5a042 1032
Wayne Roberts 0:6b3ac9c5a042 1033 // Store downlink datarate
Wayne Roberts 0:6b3ac9c5a042 1034 McpsIndication.RxDatarate = ( uint8_t ) datarate;
Wayne Roberts 0:6b3ac9c5a042 1035
Wayne Roberts 0:6b3ac9c5a042 1036 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868) || defined(USE_BAND_ARIB_8CH)
Wayne Roberts 0:6b3ac9c5a042 1037 if( datarate == DR_7 )
Wayne Roberts 0:6b3ac9c5a042 1038 {
Wayne Roberts 0:6b3ac9c5a042 1039 modem = MODEM_FSK;
Wayne Roberts 0:6b3ac9c5a042 1040 Radio::SetRxConfig( modem, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, 0, false, 0, true, false);
Wayne Roberts 0:6b3ac9c5a042 1041 }
Wayne Roberts 0:6b3ac9c5a042 1042 else
Wayne Roberts 0:6b3ac9c5a042 1043 {
Wayne Roberts 0:6b3ac9c5a042 1044 modem = MODEM_LORA;
Wayne Roberts 0:6b3ac9c5a042 1045 Radio::SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, true);
Wayne Roberts 0:6b3ac9c5a042 1046 }
Wayne Roberts 0:6b3ac9c5a042 1047 #elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1048 modem = MODEM_LORA;
Wayne Roberts 0:6b3ac9c5a042 1049 Radio::SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, true);
Wayne Roberts 0:6b3ac9c5a042 1050 #endif
Wayne Roberts 0:6b3ac9c5a042 1051
Wayne Roberts 0:6b3ac9c5a042 1052 Radio::SetRxMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD );
Wayne Roberts 0:6b3ac9c5a042 1053 } //..RxWindowSetup()
Wayne Roberts 0:6b3ac9c5a042 1054
Wayne Roberts 7:4b6f960dcca2 1055 LowPowerTimeout RxWindowEvent1;
Wayne Roberts 7:4b6f960dcca2 1056 LowPowerTimeout RxWindowEvent2;
Wayne Roberts 7:4b6f960dcca2 1057
Wayne Roberts 0:6b3ac9c5a042 1058 static void RxWindow2Start( void )
Wayne Roberts 0:6b3ac9c5a042 1059 {
Wayne Roberts 0:6b3ac9c5a042 1060 /* TODO: join accept rx2 channel unique */
Wayne Roberts 0:6b3ac9c5a042 1061 if (LoRaMacDeviceClass == CLASS_C)
Wayne Roberts 0:6b3ac9c5a042 1062 Radio::Rx( 0 ); // Continuous mode
Wayne Roberts 0:6b3ac9c5a042 1063 else
Wayne Roberts 0:6b3ac9c5a042 1064 Radio::Rx( LoRaMacParams.MaxRxWindow_us );
Wayne Roberts 0:6b3ac9c5a042 1065
Wayne Roberts 0:6b3ac9c5a042 1066 McpsIndication.RxSlot = 2;
Wayne Roberts 0:6b3ac9c5a042 1067 }
Wayne Roberts 0:6b3ac9c5a042 1068
Wayne Roberts 0:6b3ac9c5a042 1069 static void mlme_confirm(LoRaMacEventInfoStatus_t status)
Wayne Roberts 0:6b3ac9c5a042 1070 {
Wayne Roberts 0:6b3ac9c5a042 1071 MlmeConfirm.Status = status;
Wayne Roberts 0:6b3ac9c5a042 1072
Wayne Roberts 0:6b3ac9c5a042 1073 if (MlmeConfirm.MlmeRequest != MLME_NONE) {
Wayne Roberts 0:6b3ac9c5a042 1074 if (LoRaMacPrimitives->MacMlmeConfirm != NULL)
Wayne Roberts 0:6b3ac9c5a042 1075 LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
Wayne Roberts 0:6b3ac9c5a042 1076
Wayne Roberts 0:6b3ac9c5a042 1077 MlmeConfirm.MlmeRequest = MLME_NONE;
Wayne Roberts 0:6b3ac9c5a042 1078 MlmeIndication.MlmeIndication = MLME_NONE;
Wayne Roberts 0:6b3ac9c5a042 1079 }
Wayne Roberts 0:6b3ac9c5a042 1080 }
Wayne Roberts 0:6b3ac9c5a042 1081
Wayne Roberts 0:6b3ac9c5a042 1082 static void mcps_confirm(LoRaMacEventInfoStatus_t status)
Wayne Roberts 0:6b3ac9c5a042 1083 {
Wayne Roberts 0:6b3ac9c5a042 1084 McpsConfirm.Status = status;
Wayne Roberts 0:6b3ac9c5a042 1085
Wayne Roberts 0:6b3ac9c5a042 1086 if (McpsConfirm.McpsRequest != MCPS_NONE) {
Wayne Roberts 0:6b3ac9c5a042 1087 if (LoRaMacPrimitives->MacMcpsConfirm)
Wayne Roberts 0:6b3ac9c5a042 1088 LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm );
Wayne Roberts 0:6b3ac9c5a042 1089
Wayne Roberts 0:6b3ac9c5a042 1090 McpsConfirm.McpsRequest = MCPS_NONE;
Wayne Roberts 0:6b3ac9c5a042 1091 }
Wayne Roberts 0:6b3ac9c5a042 1092 }
Wayne Roberts 0:6b3ac9c5a042 1093
Wayne Roberts 0:6b3ac9c5a042 1094 #if defined(LORAWAN_JOIN_EUI)
Wayne Roberts 0:6b3ac9c5a042 1095 static struct {
Wayne Roberts 0:6b3ac9c5a042 1096 bool forced;
Wayne Roberts 0:6b3ac9c5a042 1097 uint8_t dr;
Wayne Roberts 0:6b3ac9c5a042 1098 uint8_t type;
Wayne Roberts 0:6b3ac9c5a042 1099 uint8_t retries;
Wayne Roberts 0:6b3ac9c5a042 1100 uint8_t Period;
Wayne Roberts 0:6b3ac9c5a042 1101 LowPowerTimeout event;
Wayne Roberts 0:6b3ac9c5a042 1102 struct {
Wayne Roberts 0:6b3ac9c5a042 1103 uint8_t MaxTimeN;
Wayne Roberts 0:6b3ac9c5a042 1104 uint8_t MaxCountN;
Wayne Roberts 0:6b3ac9c5a042 1105 unsigned uplinks_since;
Wayne Roberts 0:6b3ac9c5a042 1106 bool enabled;
Wayne Roberts 0:6b3ac9c5a042 1107 } type0;
Wayne Roberts 0:6b3ac9c5a042 1108 } rejoin;
Wayne Roberts 0:6b3ac9c5a042 1109 void _rejoin_retry(void);
Wayne Roberts 0:6b3ac9c5a042 1110
Wayne Roberts 0:6b3ac9c5a042 1111 void rejoin_retry()
Wayne Roberts 0:6b3ac9c5a042 1112 {
Wayne Roberts 0:6b3ac9c5a042 1113 LoRaMacStatus_t status;
Wayne Roberts 0:6b3ac9c5a042 1114 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 1115
Wayne Roberts 0:6b3ac9c5a042 1116 macHdr.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 1117 macHdr.Bits.MType = FRAME_TYPE_REJOIN_REQ;
Wayne Roberts 0:6b3ac9c5a042 1118 LoRaMacParams.ChannelsDatarate = rejoin.dr;
Wayne Roberts 0:6b3ac9c5a042 1119 JoinReqType = rejoin.type;
Wayne Roberts 0:6b3ac9c5a042 1120 status = Send( &macHdr, 0, NULL, 0 );
Wayne Roberts 0:6b3ac9c5a042 1121 if (status != LORAMAC_STATUS_OK) {
Wayne Roberts 0:6b3ac9c5a042 1122 MAC_PRINTF("rejoin-send-failed%d ", status);
Wayne Roberts 0:6b3ac9c5a042 1123 }
Wayne Roberts 0:6b3ac9c5a042 1124
Wayne Roberts 0:6b3ac9c5a042 1125 MAC_PRINTF("Rejoin%u ", JoinReqType);
Wayne Roberts 0:6b3ac9c5a042 1126 if (rejoin.forced) {
Wayne Roberts 0:6b3ac9c5a042 1127 if (--rejoin.retries > 0) {
Wayne Roberts 0:6b3ac9c5a042 1128 us_timestamp_t period_us = (1 << rejoin.Period) + random_at_most(32000000);
Wayne Roberts 0:6b3ac9c5a042 1129 rejoin.event.attach_us(_rejoin_retry, period_us);
Wayne Roberts 0:6b3ac9c5a042 1130 MAC_PRINTF("try%u", rejoin.retries);
Wayne Roberts 0:6b3ac9c5a042 1131 } else
Wayne Roberts 0:6b3ac9c5a042 1132 rejoin.forced = false;
Wayne Roberts 0:6b3ac9c5a042 1133 }
Wayne Roberts 0:6b3ac9c5a042 1134 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 1135 }
Wayne Roberts 0:6b3ac9c5a042 1136
Wayne Roberts 0:6b3ac9c5a042 1137 void _rejoin_retry()
Wayne Roberts 0:6b3ac9c5a042 1138 {
Wayne Roberts 0:6b3ac9c5a042 1139 if (flags.uplink_in_progress > 0) {
Wayne Roberts 0:6b3ac9c5a042 1140 function_pending = rejoin_retry;
Wayne Roberts 0:6b3ac9c5a042 1141 } else
Wayne Roberts 0:6b3ac9c5a042 1142 rejoin_retry();
Wayne Roberts 0:6b3ac9c5a042 1143 }
Wayne Roberts 0:6b3ac9c5a042 1144 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1145
Wayne Roberts 0:6b3ac9c5a042 1146 void
Wayne Roberts 0:6b3ac9c5a042 1147 finish_uplink(LoRaMacEventInfoStatus_t status)
Wayne Roberts 0:6b3ac9c5a042 1148 {
Wayne Roberts 3:eb174e10afbb 1149 if ((flags.uplink_in_progress > 0 && McpsIndication.RxSlot == 2) || status == LORAMAC_EVENT_INFO_STATUS_OK) {
Wayne Roberts 7:4b6f960dcca2 1150 if ((uplinkMHDR->Bits.MType == FRAME_TYPE_DATA_CONFIRMED_UP && status == LORAMAC_EVENT_INFO_STATUS_OK) || uplinkMHDR->Bits.MType != FRAME_TYPE_DATA_CONFIRMED_UP) {
Wayne Roberts 3:eb174e10afbb 1151 flags.uplink_in_progress--;
Wayne Roberts 7:4b6f960dcca2 1152 }
Wayne Roberts 3:eb174e10afbb 1153
Wayne Roberts 0:6b3ac9c5a042 1154 if (flags.uplink_in_progress > 0) {
Wayne Roberts 3:eb174e10afbb 1155 McpsIndication.Status = status;
Wayne Roberts 3:eb174e10afbb 1156 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 3:eb174e10afbb 1157 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
Wayne Roberts 3:eb174e10afbb 1158
Wayne Roberts 0:6b3ac9c5a042 1159 if (flags.rxing)
Wayne Roberts 0:6b3ac9c5a042 1160 function_pending = region_ScheduleTx;
Wayne Roberts 0:6b3ac9c5a042 1161 else {
Wayne Roberts 0:6b3ac9c5a042 1162 region_ScheduleTx( );
Wayne Roberts 0:6b3ac9c5a042 1163 }
Wayne Roberts 0:6b3ac9c5a042 1164 } else
Wayne Roberts 0:6b3ac9c5a042 1165 region_session_start(status);
Wayne Roberts 0:6b3ac9c5a042 1166 }
Wayne Roberts 0:6b3ac9c5a042 1167
Wayne Roberts 0:6b3ac9c5a042 1168 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1169 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 1170 macHdr.Value = Radio::radio.tx_buf[0];
Wayne Roberts 0:6b3ac9c5a042 1171 if (macHdr.Bits.MType != FRAME_TYPE_REJOIN_REQ) {
Wayne Roberts 0:6b3ac9c5a042 1172 if (rejoin.type0.enabled && --rejoin.type0.uplinks_since == 0) {
Wayne Roberts 0:6b3ac9c5a042 1173 rejoin.type0.uplinks_since = 1 << (rejoin.type0.MaxCountN + 4);
Wayne Roberts 0:6b3ac9c5a042 1174
Wayne Roberts 0:6b3ac9c5a042 1175 rejoin.type = 0;
Wayne Roberts 0:6b3ac9c5a042 1176 rejoin_retry();
Wayne Roberts 0:6b3ac9c5a042 1177 return;
Wayne Roberts 0:6b3ac9c5a042 1178 }
Wayne Roberts 0:6b3ac9c5a042 1179 }
Wayne Roberts 0:6b3ac9c5a042 1180 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1181
Wayne Roberts 5:4e9d41359897 1182 waitingFor = LORAMAC_STATUS_OK;
Wayne Roberts 5:4e9d41359897 1183
Wayne Roberts 0:6b3ac9c5a042 1184 if (function_pending != NULL) {
Wayne Roberts 0:6b3ac9c5a042 1185 function_pending();
Wayne Roberts 0:6b3ac9c5a042 1186 function_pending = NULL;
Wayne Roberts 0:6b3ac9c5a042 1187 }
Wayne Roberts 0:6b3ac9c5a042 1188 } // ..finish_uplink()
Wayne Roberts 0:6b3ac9c5a042 1189
Wayne Roberts 0:6b3ac9c5a042 1190 LowPowerTimeout TxDelayedEvent;
Wayne Roberts 0:6b3ac9c5a042 1191
Wayne Roberts 4:e4bfe9183f94 1192 void OnTxDelayedIsr()
Wayne Roberts 4:e4bfe9183f94 1193 {
Wayne Roberts 4:e4bfe9183f94 1194 flags.OnTxDelayed = true;
Wayne Roberts 4:e4bfe9183f94 1195 }
Wayne Roberts 4:e4bfe9183f94 1196
Wayne Roberts 4:e4bfe9183f94 1197 static void OnTxDelayedTimerEvent()
Wayne Roberts 0:6b3ac9c5a042 1198 {
Wayne Roberts 0:6b3ac9c5a042 1199 MAC_PRINTF("OnTxDelayedTimerEvent() ");
Wayne Roberts 0:6b3ac9c5a042 1200 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1201 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 1202 LoRaMacFrameCtrl_t fCtrl;
Wayne Roberts 0:6b3ac9c5a042 1203
Wayne Roberts 0:6b3ac9c5a042 1204 if (!flags.IsLoRaMacNetworkJoined)
Wayne Roberts 0:6b3ac9c5a042 1205 {
Wayne Roberts 0:6b3ac9c5a042 1206 // Add a +1, since we start to count from 0
Wayne Roberts 3:eb174e10afbb 1207 LoRaMacParams.ChannelsDatarate = region_AlternateDatarate( MlmeIndication.JoinRequestTrials + 1 );
Wayne Roberts 0:6b3ac9c5a042 1208
Wayne Roberts 0:6b3ac9c5a042 1209 macHdr.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 1210 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
Wayne Roberts 0:6b3ac9c5a042 1211
Wayne Roberts 0:6b3ac9c5a042 1212 fCtrl.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 1213 fCtrl.Bits.Adr = flags.AdrCtrlOn;
Wayne Roberts 0:6b3ac9c5a042 1214
Wayne Roberts 0:6b3ac9c5a042 1215 /* In case of join request retransmissions, the stack must prepare
Wayne Roberts 0:6b3ac9c5a042 1216 * the frame again, because the network server keeps track of the random
Wayne Roberts 0:6b3ac9c5a042 1217 * LoRaMacDevNonce values to prevent reply attacks. */
Wayne Roberts 0:6b3ac9c5a042 1218 PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 );
Wayne Roberts 0:6b3ac9c5a042 1219 /* TODO PrepareFrame() != LORAMAC_STATUS_OK */
Wayne Roberts 0:6b3ac9c5a042 1220 }
Wayne Roberts 0:6b3ac9c5a042 1221 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1222
Wayne Roberts 0:6b3ac9c5a042 1223 if (flags.rxing)
Wayne Roberts 0:6b3ac9c5a042 1224 function_pending = region_ScheduleTx;
Wayne Roberts 0:6b3ac9c5a042 1225 else {
Wayne Roberts 0:6b3ac9c5a042 1226 region_ScheduleTx( );
Wayne Roberts 0:6b3ac9c5a042 1227 }
Wayne Roberts 0:6b3ac9c5a042 1228 } // ..OnTxDelayedTimerEvent()
Wayne Roberts 0:6b3ac9c5a042 1229
Wayne Roberts 0:6b3ac9c5a042 1230 static void RxWindow2Setup(void)
Wayne Roberts 0:6b3ac9c5a042 1231 {
Wayne Roberts 0:6b3ac9c5a042 1232 MAC_PRINTF("RxWindow2Setup %uhz dr%u", LoRaMacParams.Rx2Channel.FrequencyHz, LoRaMacParams.Rx2Channel.Datarate);
Wayne Roberts 0:6b3ac9c5a042 1233 RxWindowSetup(
Wayne Roberts 0:6b3ac9c5a042 1234 LoRaMacParams.Rx2Channel.FrequencyHz,
Wayne Roberts 0:6b3ac9c5a042 1235 LoRaMacParams.Rx2Channel.Datarate,
Wayne Roberts 0:6b3ac9c5a042 1236 region_GetRxBandwidth( LoRaMacParams.Rx2Channel.Datarate ),
Wayne Roberts 0:6b3ac9c5a042 1237 region_GetRxSymbolTimeout( LoRaMacParams.Rx2Channel.Datarate )
Wayne Roberts 0:6b3ac9c5a042 1238 );
Wayne Roberts 5:4e9d41359897 1239
Wayne Roberts 5:4e9d41359897 1240 waitingFor = LORAMAC_STATUS_WAITING_FOR_RX2;
Wayne Roberts 0:6b3ac9c5a042 1241 }
Wayne Roberts 0:6b3ac9c5a042 1242
Wayne Roberts 0:6b3ac9c5a042 1243 static void
Wayne Roberts 0:6b3ac9c5a042 1244 PrepareRxDoneAbort(LoRaMacEventInfoStatus_t status)
Wayne Roberts 0:6b3ac9c5a042 1245 {
Wayne Roberts 0:6b3ac9c5a042 1246 MAC_PRINTF("rxAbort ");
Wayne Roberts 0:6b3ac9c5a042 1247 if( ( McpsIndication.RxSlot == 1 ) && ( LoRaMacDeviceClass == CLASS_C ) )
Wayne Roberts 0:6b3ac9c5a042 1248 {
Wayne Roberts 0:6b3ac9c5a042 1249 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 1250 RxWindow2Start(); // start continuous rx2 reception
Wayne Roberts 0:6b3ac9c5a042 1251 }
Wayne Roberts 0:6b3ac9c5a042 1252
Wayne Roberts 0:6b3ac9c5a042 1253 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1254 if (!flags.IsLoRaMacNetworkJoined && LoRaMacJoinEui != NULL && LoRaMacDevEui == NULL) {
Wayne Roberts 4:e4bfe9183f94 1255 TxDelayedEvent.attach_us(OnTxDelayedIsr, 1000000);
Wayne Roberts 0:6b3ac9c5a042 1256 MAC_PRINTF("RxDoneAbort-join-tx-delay");
Wayne Roberts 0:6b3ac9c5a042 1257 }
Wayne Roberts 0:6b3ac9c5a042 1258 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1259
Wayne Roberts 0:6b3ac9c5a042 1260
Wayne Roberts 0:6b3ac9c5a042 1261 McpsIndication.Status = status;
Wayne Roberts 0:6b3ac9c5a042 1262 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 1263 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); // RxAbort
Wayne Roberts 0:6b3ac9c5a042 1264
Wayne Roberts 0:6b3ac9c5a042 1265 mcps_confirm(status); // RXAbort
Wayne Roberts 0:6b3ac9c5a042 1266 mlme_confirm(status);
Wayne Roberts 0:6b3ac9c5a042 1267
Wayne Roberts 0:6b3ac9c5a042 1268 finish_uplink(status);
Wayne Roberts 0:6b3ac9c5a042 1269
Wayne Roberts 0:6b3ac9c5a042 1270 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 1271
Wayne Roberts 0:6b3ac9c5a042 1272 } // ..PrepareRxDoneAbort()
Wayne Roberts 0:6b3ac9c5a042 1273
Wayne Roberts 0:6b3ac9c5a042 1274
Wayne Roberts 0:6b3ac9c5a042 1275 static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
Wayne Roberts 0:6b3ac9c5a042 1276 {
Wayne Roberts 0:6b3ac9c5a042 1277 LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1278
Wayne Roberts 0:6b3ac9c5a042 1279 switch( LoRaMacDeviceClass )
Wayne Roberts 0:6b3ac9c5a042 1280 {
Wayne Roberts 0:6b3ac9c5a042 1281 case CLASS_A:
Wayne Roberts 0:6b3ac9c5a042 1282 {
Wayne Roberts 0:6b3ac9c5a042 1283 MAC_PRINTF("CLASS_A ");
Wayne Roberts 0:6b3ac9c5a042 1284 if (deviceClass == CLASS_B)
Wayne Roberts 0:6b3ac9c5a042 1285 status = SwitchClassB(deviceClass);
Wayne Roberts 0:6b3ac9c5a042 1286
Wayne Roberts 0:6b3ac9c5a042 1287 if (deviceClass == CLASS_C)
Wayne Roberts 0:6b3ac9c5a042 1288 {
Wayne Roberts 0:6b3ac9c5a042 1289 MAC_PRINTF("->C ");
Wayne Roberts 0:6b3ac9c5a042 1290 LoRaMacDeviceClass = deviceClass;
Wayne Roberts 0:6b3ac9c5a042 1291 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 1292 RxWindow2Start(); // continuous rx2 reception
Wayne Roberts 7:4b6f960dcca2 1293 if (flags.OptNeg) {
Wayne Roberts 7:4b6f960dcca2 1294 AddMacCommand(MOTE_MAC_MODE_IND, LoRaMacDeviceClass, 0);
Wayne Roberts 7:4b6f960dcca2 1295 }
Wayne Roberts 0:6b3ac9c5a042 1296
Wayne Roberts 0:6b3ac9c5a042 1297 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1298 }
Wayne Roberts 0:6b3ac9c5a042 1299 break;
Wayne Roberts 0:6b3ac9c5a042 1300 }
Wayne Roberts 0:6b3ac9c5a042 1301 case CLASS_B:
Wayne Roberts 0:6b3ac9c5a042 1302 {
Wayne Roberts 0:6b3ac9c5a042 1303 MAC_PRINTF("CLASS_B ");
Wayne Roberts 0:6b3ac9c5a042 1304 if( deviceClass == CLASS_A )
Wayne Roberts 0:6b3ac9c5a042 1305 {
Wayne Roberts 0:6b3ac9c5a042 1306 MAC_PRINTF("->A ");
Wayne Roberts 0:6b3ac9c5a042 1307 LoRaMacDeviceClass = deviceClass;
Wayne Roberts 0:6b3ac9c5a042 1308 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1309 }
Wayne Roberts 0:6b3ac9c5a042 1310 break;
Wayne Roberts 0:6b3ac9c5a042 1311 }
Wayne Roberts 0:6b3ac9c5a042 1312 case CLASS_C:
Wayne Roberts 0:6b3ac9c5a042 1313 {
Wayne Roberts 0:6b3ac9c5a042 1314 MAC_PRINTF("CLASS_C ");
Wayne Roberts 0:6b3ac9c5a042 1315 if( deviceClass == CLASS_A )
Wayne Roberts 0:6b3ac9c5a042 1316 {
Wayne Roberts 0:6b3ac9c5a042 1317 MAC_PRINTF("->A ");
Wayne Roberts 0:6b3ac9c5a042 1318 LoRaMacDeviceClass = deviceClass;
Wayne Roberts 7:4b6f960dcca2 1319 if (flags.OptNeg) {
Wayne Roberts 7:4b6f960dcca2 1320 AddMacCommand(MOTE_MAC_MODE_IND, LoRaMacDeviceClass, 0);
Wayne Roberts 7:4b6f960dcca2 1321 }
Wayne Roberts 0:6b3ac9c5a042 1322
Wayne Roberts 0:6b3ac9c5a042 1323 // Set the radio into sleep to setup a defined state
Wayne Roberts 8:5a5ea7cc946f 1324 Radio::Sleep();
Wayne Roberts 0:6b3ac9c5a042 1325
Wayne Roberts 0:6b3ac9c5a042 1326 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1327 }
Wayne Roberts 0:6b3ac9c5a042 1328 break;
Wayne Roberts 0:6b3ac9c5a042 1329 }
Wayne Roberts 0:6b3ac9c5a042 1330 }
Wayne Roberts 0:6b3ac9c5a042 1331
Wayne Roberts 0:6b3ac9c5a042 1332 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 1333 return status;
Wayne Roberts 0:6b3ac9c5a042 1334 }
Wayne Roberts 0:6b3ac9c5a042 1335
Wayne Roberts 0:6b3ac9c5a042 1336 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 1337 LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
Wayne Roberts 0:6b3ac9c5a042 1338 {
Wayne Roberts 0:6b3ac9c5a042 1339 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1340
Wayne Roberts 0:6b3ac9c5a042 1341 if (mibSet == NULL)
Wayne Roberts 0:6b3ac9c5a042 1342 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1343
Wayne Roberts 0:6b3ac9c5a042 1344 if (flags.uplink_in_progress > 0)
Wayne Roberts 5:4e9d41359897 1345 return waitingFor;
Wayne Roberts 0:6b3ac9c5a042 1346
Wayne Roberts 0:6b3ac9c5a042 1347 switch (mibSet->Type) {
Wayne Roberts 0:6b3ac9c5a042 1348 case MIB_CHANNELS_MASK:
Wayne Roberts 0:6b3ac9c5a042 1349 if( mibSet->Param.ChannelsMask )
Wayne Roberts 0:6b3ac9c5a042 1350 {
Wayne Roberts 0:6b3ac9c5a042 1351 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1352 bool chanMaskState = true;
Wayne Roberts 0:6b3ac9c5a042 1353
Wayne Roberts 0:6b3ac9c5a042 1354 #if defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1355 chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsMask );
Wayne Roberts 0:6b3ac9c5a042 1356 #endif
Wayne Roberts 0:6b3ac9c5a042 1357 if( chanMaskState == true )
Wayne Roberts 0:6b3ac9c5a042 1358 {
Wayne Roberts 0:6b3ac9c5a042 1359 if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) &&
Wayne Roberts 0:6b3ac9c5a042 1360 ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
Wayne Roberts 0:6b3ac9c5a042 1361 {
Wayne Roberts 0:6b3ac9c5a042 1362 status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1363 }
Wayne Roberts 0:6b3ac9c5a042 1364 else
Wayne Roberts 0:6b3ac9c5a042 1365 {
Wayne Roberts 0:6b3ac9c5a042 1366 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask,
Wayne Roberts 0:6b3ac9c5a042 1367 ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
Wayne Roberts 0:6b3ac9c5a042 1368 for ( uint8_t i = 0; i < sizeof( LoRaMacParams.ChannelsMask ) / 2; i++ )
Wayne Roberts 0:6b3ac9c5a042 1369 {
Wayne Roberts 0:6b3ac9c5a042 1370 // Disable channels which are no longer available
Wayne Roberts 0:6b3ac9c5a042 1371 ChannelsMaskRemaining[i] &= LoRaMacParams.ChannelsMask[i];
Wayne Roberts 0:6b3ac9c5a042 1372 }
Wayne Roberts 0:6b3ac9c5a042 1373 }
Wayne Roberts 0:6b3ac9c5a042 1374 }
Wayne Roberts 0:6b3ac9c5a042 1375 else
Wayne Roberts 0:6b3ac9c5a042 1376 {
Wayne Roberts 0:6b3ac9c5a042 1377 status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1378 }
Wayne Roberts 0:6b3ac9c5a042 1379 #elif defined( USE_BAND_470 )
Wayne Roberts 0:6b3ac9c5a042 1380 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask,
Wayne Roberts 0:6b3ac9c5a042 1381 ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
Wayne Roberts 0:6b3ac9c5a042 1382 #else
Wayne Roberts 0:6b3ac9c5a042 1383 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask,
Wayne Roberts 0:6b3ac9c5a042 1384 ( uint8_t* ) mibSet->Param.ChannelsMask, 2 );
Wayne Roberts 0:6b3ac9c5a042 1385 #endif
Wayne Roberts 3:eb174e10afbb 1386 LoRaMacParams.NbEnabledChannels = region_CountNbEnabledChannels();
Wayne Roberts 0:6b3ac9c5a042 1387 }
Wayne Roberts 0:6b3ac9c5a042 1388 else
Wayne Roberts 0:6b3ac9c5a042 1389 {
Wayne Roberts 0:6b3ac9c5a042 1390 status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1391 }
Wayne Roberts 0:6b3ac9c5a042 1392 break;
Wayne Roberts 0:6b3ac9c5a042 1393 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1394 /* values which cannot be set in OTA */
Wayne Roberts 0:6b3ac9c5a042 1395 case MIB_NwkSKey:
Wayne Roberts 0:6b3ac9c5a042 1396 case MIB_SNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 1397 case MIB_NwkSEncKey:
Wayne Roberts 0:6b3ac9c5a042 1398 case MIB_FNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 1399 case MIB_APP_SKEY:
Wayne Roberts 0:6b3ac9c5a042 1400 case MIB_DEV_ADDR:
Wayne Roberts 0:6b3ac9c5a042 1401 case MIB_NETWORK_JOINED:
Wayne Roberts 0:6b3ac9c5a042 1402 #endif
Wayne Roberts 0:6b3ac9c5a042 1403 case MIB_RX2_CHANNEL:
Wayne Roberts 0:6b3ac9c5a042 1404 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1405 case MIB_DEVICE_CLASS:
Wayne Roberts 0:6b3ac9c5a042 1406 status = SwitchClass(mibSet->Param.Class);
Wayne Roberts 0:6b3ac9c5a042 1407 break;
Wayne Roberts 0:6b3ac9c5a042 1408 case MIB_ADR:
Wayne Roberts 0:6b3ac9c5a042 1409 flags.AdrCtrlOn = mibSet->Param.AdrEnable;
Wayne Roberts 0:6b3ac9c5a042 1410 break;
Wayne Roberts 0:6b3ac9c5a042 1411 case MIB_PUBLIC_NETWORK:
Wayne Roberts 0:6b3ac9c5a042 1412 flags.PublicNetwork = mibSet->Param.EnablePublicNetwork;
Wayne Roberts 0:6b3ac9c5a042 1413 Radio::SetPublicNetwork( flags.PublicNetwork );
Wayne Roberts 0:6b3ac9c5a042 1414 break;
Wayne Roberts 7:4b6f960dcca2 1415 case MIB_MAX_LISTEN_TIME:
Wayne Roberts 7:4b6f960dcca2 1416 LoRaMacParams.MaxListenTime = mibSet->Param.MaxListenTime;
Wayne Roberts 7:4b6f960dcca2 1417 break;
Wayne Roberts 0:6b3ac9c5a042 1418 #ifndef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1419 case MIB_SNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 1420 flags.have_SNwkSIntKey = 1;
Wayne Roberts 0:6b3ac9c5a042 1421 memcpy( keys.SNwkSIntKey, mibSet->Param.key, sizeof(keys.SNwkSIntKey) );
Wayne Roberts 0:6b3ac9c5a042 1422 if (flags.have_NwkSEncKey) {
Wayne Roberts 0:6b3ac9c5a042 1423 flags.OptNeg = 1;
Wayne Roberts 0:6b3ac9c5a042 1424 flags.need_ResetConf = 1;
Wayne Roberts 0:6b3ac9c5a042 1425 }
Wayne Roberts 0:6b3ac9c5a042 1426 break;
Wayne Roberts 0:6b3ac9c5a042 1427 case MIB_NwkSEncKey:
Wayne Roberts 0:6b3ac9c5a042 1428 flags.have_NwkSEncKey = 1;
Wayne Roberts 0:6b3ac9c5a042 1429 memcpy( keys.NwkSEncKey, mibSet->Param.key, sizeof(keys.NwkSEncKey) );
Wayne Roberts 0:6b3ac9c5a042 1430 if (flags.have_SNwkSIntKey) {
Wayne Roberts 0:6b3ac9c5a042 1431 flags.OptNeg = 1;
Wayne Roberts 0:6b3ac9c5a042 1432 flags.need_ResetConf = 1;
Wayne Roberts 0:6b3ac9c5a042 1433 }
Wayne Roberts 0:6b3ac9c5a042 1434 break;
Wayne Roberts 0:6b3ac9c5a042 1435 case MIB_APP_SKEY:
Wayne Roberts 0:6b3ac9c5a042 1436 memcpy( keys.AppSKey, mibSet->Param.key, sizeof( keys.AppSKey ) );
Wayne Roberts 0:6b3ac9c5a042 1437 break;
Wayne Roberts 0:6b3ac9c5a042 1438 case MIB_FNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 1439 memcpy( keys.FNwkSIntKey, mibSet->Param.key, sizeof( keys.FNwkSIntKey ) );
Wayne Roberts 0:6b3ac9c5a042 1440 break;
Wayne Roberts 0:6b3ac9c5a042 1441 case MIB_NwkSKey:
Wayne Roberts 0:6b3ac9c5a042 1442 /* lorawan 1.0 ABP */
Wayne Roberts 0:6b3ac9c5a042 1443 memcpy( keys.FNwkSIntKey, mibSet->Param.key, sizeof( keys.FNwkSIntKey ) );
Wayne Roberts 0:6b3ac9c5a042 1444 memcpy( keys.SNwkSIntKey, mibSet->Param.key, sizeof( keys.SNwkSIntKey) );
Wayne Roberts 0:6b3ac9c5a042 1445 memcpy( keys.NwkSEncKey, mibSet->Param.key, sizeof( keys.NwkSEncKey) );
Wayne Roberts 0:6b3ac9c5a042 1446 flags.OptNeg = 0;
Wayne Roberts 0:6b3ac9c5a042 1447 break;
Wayne Roberts 0:6b3ac9c5a042 1448 case MIB_DEV_ADDR:
Wayne Roberts 0:6b3ac9c5a042 1449 LoRaMacDevAddr = mibSet->Param.DevAddr;
Wayne Roberts 0:6b3ac9c5a042 1450 break;
Wayne Roberts 0:6b3ac9c5a042 1451 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1452 } // ..switch( mibSet->Type )
Wayne Roberts 0:6b3ac9c5a042 1453
Wayne Roberts 0:6b3ac9c5a042 1454 return status;
Wayne Roberts 0:6b3ac9c5a042 1455 } // ..LoRaMacMibSetRequestConfirm()
Wayne Roberts 0:6b3ac9c5a042 1456
Wayne Roberts 0:6b3ac9c5a042 1457 __attribute__((weak)) LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 1458 LoRaMacClassBInitialization( void )
Wayne Roberts 0:6b3ac9c5a042 1459 {
Wayne Roberts 0:6b3ac9c5a042 1460 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1461 }
Wayne Roberts 0:6b3ac9c5a042 1462
Wayne Roberts 0:6b3ac9c5a042 1463
Wayne Roberts 0:6b3ac9c5a042 1464 static void RxWindow1Start( void )
dudmuck 2:c9c736b3e4eb 1465 {
Wayne Roberts 7:4b6f960dcca2 1466 if (LoRaMacDeviceClass == CLASS_C) {
Wayne Roberts 7:4b6f960dcca2 1467 Radio::Standby();
Wayne Roberts 7:4b6f960dcca2 1468 region_rx1_setup(Channel);
Wayne Roberts 7:4b6f960dcca2 1469 }
Wayne Roberts 7:4b6f960dcca2 1470
Wayne Roberts 7:4b6f960dcca2 1471 Radio::Rx( LoRaMacParams.MaxRxWindow_us );
Wayne Roberts 0:6b3ac9c5a042 1472
Wayne Roberts 0:6b3ac9c5a042 1473 McpsIndication.RxSlot = 1;
Wayne Roberts 0:6b3ac9c5a042 1474 }
Wayne Roberts 0:6b3ac9c5a042 1475
Wayne Roberts 0:6b3ac9c5a042 1476 volatile us_timestamp_t tx_done_at;
Wayne Roberts 0:6b3ac9c5a042 1477
Wayne Roberts 0:6b3ac9c5a042 1478 static void OnRadioTxDone( us_timestamp_t at_us )
Wayne Roberts 0:6b3ac9c5a042 1479 {
Wayne Roberts 0:6b3ac9c5a042 1480 if ((RxWindow1Delay_us < 100000 || RxWindow1Delay_us > 10000000) ||
Wayne Roberts 0:6b3ac9c5a042 1481 (RxWindow2Delay_us < 100000 || RxWindow2Delay_us > 10000000))
Wayne Roberts 0:6b3ac9c5a042 1482 {
Wayne Roberts 0:6b3ac9c5a042 1483 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_BAD_RX_DELAY);
Wayne Roberts 0:6b3ac9c5a042 1484 return;
Wayne Roberts 0:6b3ac9c5a042 1485 }
Wayne Roberts 0:6b3ac9c5a042 1486 // Setup timers
Wayne Roberts 0:6b3ac9c5a042 1487 RxWindowEvent1.attach_us(RxWindow1Start, RxWindow1Delay_us);
Wayne Roberts 7:4b6f960dcca2 1488 waitingFor = LORAMAC_STATUS_WAITING_FOR_RX1;
Wayne Roberts 0:6b3ac9c5a042 1489 McpsIndication.RxSlot = 0;
Wayne Roberts 0:6b3ac9c5a042 1490
Wayne Roberts 0:6b3ac9c5a042 1491 tx_done_at = at_us;
Wayne Roberts 0:6b3ac9c5a042 1492
Wayne Roberts 7:4b6f960dcca2 1493 if (LoRaMacDeviceClass != CLASS_C)
Wayne Roberts 0:6b3ac9c5a042 1494 {
Wayne Roberts 7:4b6f960dcca2 1495 RxWindowEvent2.attach_us(RxWindow2Start, RxWindow2Delay_us);
Wayne Roberts 0:6b3ac9c5a042 1496 region_rx1_setup(Channel);
Wayne Roberts 8:5a5ea7cc946f 1497 Radio::Sleep();
Wayne Roberts 0:6b3ac9c5a042 1498 }
Wayne Roberts 0:6b3ac9c5a042 1499 else
Wayne Roberts 0:6b3ac9c5a042 1500 {
Wayne Roberts 0:6b3ac9c5a042 1501 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 1502 RxWindow2Start();
Wayne Roberts 7:4b6f960dcca2 1503 // simulate timeout to complete uplink
Wayne Roberts 7:4b6f960dcca2 1504 RxWindowEvent2.attach_us(OnRadioRxTimeout, RxWindow2Delay_us + 256000);
Wayne Roberts 0:6b3ac9c5a042 1505 }
Wayne Roberts 0:6b3ac9c5a042 1506
Wayne Roberts 0:6b3ac9c5a042 1507 // Store last tx channel
Wayne Roberts 0:6b3ac9c5a042 1508 //LastTxChannel = Channel;
Wayne Roberts 0:6b3ac9c5a042 1509 #ifdef DUTY_ENABLE
Wayne Roberts 0:6b3ac9c5a042 1510 DutyTxDone(at_us);
Wayne Roberts 0:6b3ac9c5a042 1511 #endif /* DUTY_ENABLE */
Wayne Roberts 0:6b3ac9c5a042 1512
Wayne Roberts 0:6b3ac9c5a042 1513 } // ..OnRadioTxDone()
Wayne Roberts 0:6b3ac9c5a042 1514
Wayne Roberts 0:6b3ac9c5a042 1515 static void OnRadioTxTimeout( void )
Wayne Roberts 0:6b3ac9c5a042 1516 {
Wayne Roberts 0:6b3ac9c5a042 1517 if( LoRaMacDeviceClass != CLASS_C )
Wayne Roberts 0:6b3ac9c5a042 1518 {
Wayne Roberts 8:5a5ea7cc946f 1519 Radio::Sleep();
Wayne Roberts 0:6b3ac9c5a042 1520 }
Wayne Roberts 0:6b3ac9c5a042 1521 else
Wayne Roberts 0:6b3ac9c5a042 1522 {
Wayne Roberts 0:6b3ac9c5a042 1523 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 1524 RxWindow2Start();
Wayne Roberts 0:6b3ac9c5a042 1525 }
Wayne Roberts 0:6b3ac9c5a042 1526
Wayne Roberts 0:6b3ac9c5a042 1527 finish_uplink(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 1528
Wayne Roberts 0:6b3ac9c5a042 1529 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 1530 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 1531 } // ..OnRadioTxTimeout()
Wayne Roberts 0:6b3ac9c5a042 1532
Wayne Roberts 0:6b3ac9c5a042 1533 __attribute__((weak)) bool
Wayne Roberts 0:6b3ac9c5a042 1534 beacon_rx_done_payload(uint8_t* payload, uint16_t size)
Wayne Roberts 0:6b3ac9c5a042 1535 {
Wayne Roberts 0:6b3ac9c5a042 1536 return false;
Wayne Roberts 0:6b3ac9c5a042 1537 }
Wayne Roberts 0:6b3ac9c5a042 1538
Wayne Roberts 0:6b3ac9c5a042 1539 static void
Wayne Roberts 0:6b3ac9c5a042 1540 print_mtype(uint8_t mt)
Wayne Roberts 0:6b3ac9c5a042 1541 {
Wayne Roberts 0:6b3ac9c5a042 1542 #ifdef MAC_DEBUG
Wayne Roberts 0:6b3ac9c5a042 1543 const char* cp;
Wayne Roberts 0:6b3ac9c5a042 1544 switch (mt) {
Wayne Roberts 0:6b3ac9c5a042 1545 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1546 case FRAME_TYPE_JOIN_REQ: cp = "JOIN_REQ "; break;
Wayne Roberts 0:6b3ac9c5a042 1547 case FRAME_TYPE_JOIN_ACCEPT: cp = "JOIN_ACC "; break;
Wayne Roberts 0:6b3ac9c5a042 1548 case FRAME_TYPE_REJOIN_REQ: cp = "REJOIN_REQ"; break;
Wayne Roberts 0:6b3ac9c5a042 1549 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1550 case FRAME_TYPE_DATA_UNCONFIRMED_UP: cp = "UNCONF_UP"; break;
Wayne Roberts 0:6b3ac9c5a042 1551 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: cp = "UNCONF_DN"; break;
Wayne Roberts 0:6b3ac9c5a042 1552 case FRAME_TYPE_DATA_CONFIRMED_UP: cp = "CONF_UP"; break;
Wayne Roberts 0:6b3ac9c5a042 1553 case FRAME_TYPE_DATA_CONFIRMED_DOWN: cp = "CONF_DN"; break;
Wayne Roberts 0:6b3ac9c5a042 1554 case FRAME_TYPE_PROPRIETARY: cp = "P"; break;
Wayne Roberts 0:6b3ac9c5a042 1555 default: return;
Wayne Roberts 0:6b3ac9c5a042 1556 }
Wayne Roberts 0:6b3ac9c5a042 1557 MAC_PRINTF("MTYPE_%s ", cp);
Wayne Roberts 0:6b3ac9c5a042 1558 #endif /* MAC_DEBUG */
Wayne Roberts 0:6b3ac9c5a042 1559 }
Wayne Roberts 0:6b3ac9c5a042 1560
Wayne Roberts 0:6b3ac9c5a042 1561 /* bool a: true=AFCntDown, false=NFCntDown */
Wayne Roberts 0:6b3ac9c5a042 1562 uint32_t get_fcntdwn(bool a)
Wayne Roberts 0:6b3ac9c5a042 1563 {
Wayne Roberts 0:6b3ac9c5a042 1564 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1565 if (a)
Wayne Roberts 0:6b3ac9c5a042 1566 return AFCntDown;
Wayne Roberts 0:6b3ac9c5a042 1567 else
Wayne Roberts 0:6b3ac9c5a042 1568 return NFCntDown;
Wayne Roberts 0:6b3ac9c5a042 1569 #else
Wayne Roberts 0:6b3ac9c5a042 1570 if (a)
Wayne Roberts 0:6b3ac9c5a042 1571 return eeprom_read(EEPROM_AFCNTDWN);
Wayne Roberts 0:6b3ac9c5a042 1572 else
Wayne Roberts 0:6b3ac9c5a042 1573 return eeprom_read(EEPROM_NFCNTDWN);
Wayne Roberts 0:6b3ac9c5a042 1574 #endif
Wayne Roberts 0:6b3ac9c5a042 1575 }
Wayne Roberts 0:6b3ac9c5a042 1576
Wayne Roberts 0:6b3ac9c5a042 1577 __attribute__((weak)) bool
Wayne Roberts 0:6b3ac9c5a042 1578 ProcessMacCommandsClassB(uint8_t* payload, uint8_t* macIndex)
Wayne Roberts 0:6b3ac9c5a042 1579 {
Wayne Roberts 0:6b3ac9c5a042 1580 return false; /* false: not taken */
Wayne Roberts 0:6b3ac9c5a042 1581 }
Wayne Roberts 0:6b3ac9c5a042 1582
Wayne Roberts 0:6b3ac9c5a042 1583
Wayne Roberts 0:6b3ac9c5a042 1584 static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask )
Wayne Roberts 0:6b3ac9c5a042 1585 {
Wayne Roberts 0:6b3ac9c5a042 1586 if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false )
Wayne Roberts 0:6b3ac9c5a042 1587 {
Wayne Roberts 0:6b3ac9c5a042 1588 return false;
Wayne Roberts 0:6b3ac9c5a042 1589 }
Wayne Roberts 0:6b3ac9c5a042 1590 for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
Wayne Roberts 0:6b3ac9c5a042 1591 {
Wayne Roberts 0:6b3ac9c5a042 1592 for( uint8_t j = 0; j < 16; j++ )
Wayne Roberts 0:6b3ac9c5a042 1593 {
Wayne Roberts 0:6b3ac9c5a042 1594 if( ( ( channelsMask[k] & ( 1 << j ) ) != 0 ) )
Wayne Roberts 0:6b3ac9c5a042 1595 {// Check datarate validity for enabled channels
Wayne Roberts 0:6b3ac9c5a042 1596 if( ValueInRange( datarate, Channels[i + j].DrRange.Fields.Min, Channels[i + j].DrRange.Fields.Max ) == true )
Wayne Roberts 0:6b3ac9c5a042 1597 {
Wayne Roberts 0:6b3ac9c5a042 1598 // At least 1 channel has been found we can return OK.
Wayne Roberts 0:6b3ac9c5a042 1599 return true;
Wayne Roberts 0:6b3ac9c5a042 1600 }
Wayne Roberts 0:6b3ac9c5a042 1601 }
Wayne Roberts 0:6b3ac9c5a042 1602 }
Wayne Roberts 0:6b3ac9c5a042 1603 }
Wayne Roberts 0:6b3ac9c5a042 1604 return false;
Wayne Roberts 0:6b3ac9c5a042 1605 }
Wayne Roberts 0:6b3ac9c5a042 1606
Wayne Roberts 0:6b3ac9c5a042 1607 static bool Rx2FreqInRange( uint32_t freq )
Wayne Roberts 0:6b3ac9c5a042 1608 {
Wayne Roberts 0:6b3ac9c5a042 1609 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) || defined (USE_BAND_ARIB_8CH)
Wayne Roberts 0:6b3ac9c5a042 1610 if( Radio::CheckRfFrequency( freq ) == true )
Wayne Roberts 0:6b3ac9c5a042 1611 #elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1612 if( ( Radio::CheckRfFrequency( freq ) == true ) &&
Wayne Roberts 0:6b3ac9c5a042 1613 ( freq >= LORAMAC_FIRST_RX1_CHANNEL ) &&
Wayne Roberts 0:6b3ac9c5a042 1614 ( freq <= LORAMAC_LAST_RX1_CHANNEL ) &&
Wayne Roberts 0:6b3ac9c5a042 1615 ( ( ( freq - ( uint32_t ) LORAMAC_FIRST_RX1_CHANNEL ) % ( uint32_t ) LORAMAC_STEPWIDTH_RX1_CHANNEL ) == 0 ) )
Wayne Roberts 0:6b3ac9c5a042 1616 #endif
Wayne Roberts 0:6b3ac9c5a042 1617 {
Wayne Roberts 0:6b3ac9c5a042 1618 return true;
Wayne Roberts 0:6b3ac9c5a042 1619 }
Wayne Roberts 0:6b3ac9c5a042 1620 return false;
Wayne Roberts 0:6b3ac9c5a042 1621 }
Wayne Roberts 0:6b3ac9c5a042 1622
Wayne Roberts 0:6b3ac9c5a042 1623 __attribute__((weak)) void
Wayne Roberts 0:6b3ac9c5a042 1624 deviceTimeClassB(uint32_t secs, uint32_t subsecs)
Wayne Roberts 0:6b3ac9c5a042 1625 {
Wayne Roberts 0:6b3ac9c5a042 1626 }
Wayne Roberts 0:6b3ac9c5a042 1627
Wayne Roberts 0:6b3ac9c5a042 1628 /* return -1 for unknown mac cmd */
Wayne Roberts 0:6b3ac9c5a042 1629 static int
Wayne Roberts 0:6b3ac9c5a042 1630 ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr, us_timestamp_t us_rxDone_at )
Wayne Roberts 0:6b3ac9c5a042 1631 {
Wayne Roberts 0:6b3ac9c5a042 1632 uint8_t buf[2];
Wayne Roberts 0:6b3ac9c5a042 1633 int ret = 0;
Wayne Roberts 0:6b3ac9c5a042 1634
Wayne Roberts 0:6b3ac9c5a042 1635 MACC_PRINTF("ProcessMacCommands(, %u, %u,,) ", macIndex, commandsSize);
Wayne Roberts 3:eb174e10afbb 1636 while (macIndex < commandsSize)
Wayne Roberts 0:6b3ac9c5a042 1637 {
Wayne Roberts 0:6b3ac9c5a042 1638 MACC_PRINTF("ProcessMacCommands %u(0x%02x): ", macIndex, payload[macIndex]);
Wayne Roberts 0:6b3ac9c5a042 1639 // Decode Frame MAC commands
Wayne Roberts 3:eb174e10afbb 1640 switch (payload[macIndex++])
Wayne Roberts 0:6b3ac9c5a042 1641 {
Wayne Roberts 0:6b3ac9c5a042 1642 case SRV_MAC_LINK_CHECK_ANS:
Wayne Roberts 0:6b3ac9c5a042 1643 MACC_PRINTF("LINK_CHECK_ANS ");
Wayne Roberts 0:6b3ac9c5a042 1644 buf[0] = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1645 buf[1] = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1646 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1647 MlmeConfirm.fields.link.DemodMargin = buf[0];
Wayne Roberts 0:6b3ac9c5a042 1648 MlmeConfirm.fields.link.NbGateways = buf[1];
Wayne Roberts 0:6b3ac9c5a042 1649 break;
Wayne Roberts 7:4b6f960dcca2 1650 case SRV_MAC_MODE_CONF:
Wayne Roberts 7:4b6f960dcca2 1651 break;
Wayne Roberts 0:6b3ac9c5a042 1652 case SRV_MAC_LINK_ADR_REQ:
Wayne Roberts 0:6b3ac9c5a042 1653 MACC_PRINTF("LINK_ADR_REQ ");
Wayne Roberts 0:6b3ac9c5a042 1654 {
Wayne Roberts 0:6b3ac9c5a042 1655 uint8_t i;
Wayne Roberts 0:6b3ac9c5a042 1656 int8_t txPower = 0;
Wayne Roberts 0:6b3ac9c5a042 1657 uint8_t Redundancy = 0;
Wayne Roberts 0:6b3ac9c5a042 1658 adr_t adr;
Wayne Roberts 0:6b3ac9c5a042 1659
Wayne Roberts 0:6b3ac9c5a042 1660 adr.status = 0x07;
Wayne Roberts 0:6b3ac9c5a042 1661 // Initialize local copy of the channels mask array
Wayne Roberts 0:6b3ac9c5a042 1662 for( i = 0; i < 6; i++ )
Wayne Roberts 0:6b3ac9c5a042 1663 {
Wayne Roberts 0:6b3ac9c5a042 1664 adr.channelsMask[i] = LoRaMacParams.ChannelsMask[i];
Wayne Roberts 0:6b3ac9c5a042 1665 }
Wayne Roberts 0:6b3ac9c5a042 1666 adr.datarate = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1667 txPower = adr.datarate & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 1668 adr.datarate = ( adr.datarate >> 4 ) & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 1669 MACC_PRINTF("dr%u power%u ", adr.datarate, txPower);
Wayne Roberts 0:6b3ac9c5a042 1670
Wayne Roberts 0:6b3ac9c5a042 1671 if( ( flags.AdrCtrlOn == false ) &&
Wayne Roberts 0:6b3ac9c5a042 1672 ( ( LoRaMacParams.ChannelsDatarate != adr.datarate ) || ( LoRaMacParams.ChannelsTxPower != txPower ) ) )
Wayne Roberts 0:6b3ac9c5a042 1673 { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower
Wayne Roberts 0:6b3ac9c5a042 1674 MACC_PRINTF("AdrCtrlOn:%u dr%u != dr%u, %d != %d\r\n", flags.AdrCtrlOn,
Wayne Roberts 0:6b3ac9c5a042 1675 LoRaMacParams.ChannelsDatarate, adr.datarate,
Wayne Roberts 0:6b3ac9c5a042 1676 LoRaMacParams.ChannelsTxPower, txPower
Wayne Roberts 0:6b3ac9c5a042 1677 );
Wayne Roberts 0:6b3ac9c5a042 1678 // Answer the server with fail status
Wayne Roberts 0:6b3ac9c5a042 1679 // Power ACK = 0
Wayne Roberts 0:6b3ac9c5a042 1680 // Data rate ACK = 0
Wayne Roberts 0:6b3ac9c5a042 1681 // Channel mask = 0
Wayne Roberts 0:6b3ac9c5a042 1682 AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
Wayne Roberts 0:6b3ac9c5a042 1683 macIndex += 3; // Skip over the remaining bytes of the request
Wayne Roberts 0:6b3ac9c5a042 1684 break;
Wayne Roberts 0:6b3ac9c5a042 1685 }
Wayne Roberts 0:6b3ac9c5a042 1686 adr.chMask = ( uint16_t )payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1687 adr.chMask |= ( uint16_t )payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1688
Wayne Roberts 0:6b3ac9c5a042 1689 Redundancy = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1690 adr.chMaskCntl = ( Redundancy >> 4 ) & 0x07;
Wayne Roberts 3:eb174e10afbb 1691 if ((Redundancy & 0x0f) > 0)
Wayne Roberts 3:eb174e10afbb 1692 LoRaMacParams.NbTrans = Redundancy & 0x0f;
Wayne Roberts 0:6b3ac9c5a042 1693
Wayne Roberts 0:6b3ac9c5a042 1694 MACC_PRINTF("chMask:%04x chMaskCntl:%x nbTrans:%u ", adr.chMask, adr.chMaskCntl, LoRaMacParams.NbTrans);
Wayne Roberts 0:6b3ac9c5a042 1695
Wayne Roberts 0:6b3ac9c5a042 1696 region_adr_request(&adr);
Wayne Roberts 0:6b3ac9c5a042 1697
Wayne Roberts 0:6b3ac9c5a042 1698 if( ValidateDatarate( adr.datarate, adr.channelsMask ) == false )
Wayne Roberts 0:6b3ac9c5a042 1699 {
Wayne Roberts 0:6b3ac9c5a042 1700 MACC_PRINTF("badDr ");
Wayne Roberts 0:6b3ac9c5a042 1701 adr.status &= 0xFD; // Datarate KO
Wayne Roberts 0:6b3ac9c5a042 1702 }
Wayne Roberts 0:6b3ac9c5a042 1703
Wayne Roberts 0:6b3ac9c5a042 1704 //
Wayne Roberts 0:6b3ac9c5a042 1705 // Remark MaxTxPower = 0 and MinTxPower = 5
Wayne Roberts 0:6b3ac9c5a042 1706 //
Wayne Roberts 0:6b3ac9c5a042 1707 if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
Wayne Roberts 0:6b3ac9c5a042 1708 {
Wayne Roberts 0:6b3ac9c5a042 1709 MACC_PRINTF("badPower(max:%d given:%d min:%d) ", LORAMAC_MAX_TX_POWER, txPower, LORAMAC_MIN_TX_POWER);
Wayne Roberts 0:6b3ac9c5a042 1710 adr.status &= 0xFB; // TxPower KO
Wayne Roberts 0:6b3ac9c5a042 1711 }
Wayne Roberts 0:6b3ac9c5a042 1712 MACC_PRINTF("status:%x (idx %u) ", adr.status, macIndex);
Wayne Roberts 0:6b3ac9c5a042 1713 if( ( adr.status & 0x07 ) == 0x07 )
Wayne Roberts 0:6b3ac9c5a042 1714 {
Wayne Roberts 0:6b3ac9c5a042 1715 LoRaMacParams.ChannelsDatarate = adr.datarate;
Wayne Roberts 0:6b3ac9c5a042 1716 LoRaMacParams.ChannelsTxPower = txPower;
Wayne Roberts 0:6b3ac9c5a042 1717
Wayne Roberts 0:6b3ac9c5a042 1718 memcpy( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )adr.channelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
Wayne Roberts 3:eb174e10afbb 1719 LoRaMacParams.NbEnabledChannels = region_CountNbEnabledChannels();
Wayne Roberts 0:6b3ac9c5a042 1720
Wayne Roberts 0:6b3ac9c5a042 1721 }
Wayne Roberts 0:6b3ac9c5a042 1722 AddMacCommand( MOTE_MAC_LINK_ADR_ANS, adr.status, 0 );
Wayne Roberts 0:6b3ac9c5a042 1723 }
Wayne Roberts 0:6b3ac9c5a042 1724 break;
Wayne Roberts 0:6b3ac9c5a042 1725 case SRV_MAC_RX_PARAM_SETUP_REQ:
Wayne Roberts 0:6b3ac9c5a042 1726 {
Wayne Roberts 0:6b3ac9c5a042 1727 uint8_t status = 0x07;
Wayne Roberts 0:6b3ac9c5a042 1728 int8_t datarate = 0;
Wayne Roberts 0:6b3ac9c5a042 1729 int8_t drOffset = 0;
Wayne Roberts 0:6b3ac9c5a042 1730 uint32_t freq = 0;
Wayne Roberts 0:6b3ac9c5a042 1731
Wayne Roberts 0:6b3ac9c5a042 1732 drOffset = ( payload[macIndex] >> 4 ) & 0x07;
Wayne Roberts 0:6b3ac9c5a042 1733 datarate = payload[macIndex] & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 1734 macIndex++;
Wayne Roberts 0:6b3ac9c5a042 1735
Wayne Roberts 0:6b3ac9c5a042 1736 freq = ( uint32_t )payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1737 freq |= ( uint32_t )payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1738 freq |= ( uint32_t )payload[macIndex++] << 16;
Wayne Roberts 0:6b3ac9c5a042 1739 freq *= 100;
Wayne Roberts 0:6b3ac9c5a042 1740 MACC_PRINTF("RX_PARAM_SETUP_REQ %uhz drOffset:%u dr%u ", freq, drOffset, datarate);
Wayne Roberts 0:6b3ac9c5a042 1741
Wayne Roberts 0:6b3ac9c5a042 1742 if( Rx2FreqInRange( freq ) == false )
Wayne Roberts 0:6b3ac9c5a042 1743 {
Wayne Roberts 0:6b3ac9c5a042 1744 status &= 0xFE; // Channel frequency KO
Wayne Roberts 0:6b3ac9c5a042 1745 }
Wayne Roberts 0:6b3ac9c5a042 1746
Wayne Roberts 0:6b3ac9c5a042 1747 if( ValueInRange( datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE ) == false )
Wayne Roberts 0:6b3ac9c5a042 1748 {
Wayne Roberts 0:6b3ac9c5a042 1749 status &= 0xFD; // Datarate KO
Wayne Roberts 0:6b3ac9c5a042 1750 }
Wayne Roberts 0:6b3ac9c5a042 1751 #if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
Wayne Roberts 0:6b3ac9c5a042 1752 if( ( ValueInRange( datarate, DR_5, DR_7 ) == true ) ||
Wayne Roberts 0:6b3ac9c5a042 1753 ( datarate > DR_13 ) )
Wayne Roberts 0:6b3ac9c5a042 1754 {
Wayne Roberts 0:6b3ac9c5a042 1755 status &= 0xFD; // Datarate KO
Wayne Roberts 0:6b3ac9c5a042 1756 }
Wayne Roberts 0:6b3ac9c5a042 1757 #endif
Wayne Roberts 0:6b3ac9c5a042 1758 if( ValueInRange( drOffset, LORAMAC_MIN_RX1_DR_OFFSET, LORAMAC_MAX_RX1_DR_OFFSET ) == false )
Wayne Roberts 0:6b3ac9c5a042 1759 {
Wayne Roberts 0:6b3ac9c5a042 1760 status &= 0xFB; // Rx1DrOffset range KO
Wayne Roberts 0:6b3ac9c5a042 1761 }
Wayne Roberts 0:6b3ac9c5a042 1762
Wayne Roberts 0:6b3ac9c5a042 1763 MACC_PRINTF("status:0x%02x ", status);
Wayne Roberts 0:6b3ac9c5a042 1764 if( ( status & 0x07 ) == 0x07 )
Wayne Roberts 0:6b3ac9c5a042 1765 {
Wayne Roberts 0:6b3ac9c5a042 1766 LoRaMacParams.Rx2Channel.Datarate = datarate;
Wayne Roberts 0:6b3ac9c5a042 1767 LoRaMacParams.Rx2Channel.FrequencyHz = freq;
Wayne Roberts 0:6b3ac9c5a042 1768 LoRaMacParams.Rx1DrOffset = drOffset;
Wayne Roberts 0:6b3ac9c5a042 1769 }
Wayne Roberts 0:6b3ac9c5a042 1770 AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 );
Wayne Roberts 0:6b3ac9c5a042 1771 }
Wayne Roberts 0:6b3ac9c5a042 1772 break;
Wayne Roberts 0:6b3ac9c5a042 1773 case SRV_MAC_DEV_STATUS_REQ:
Wayne Roberts 0:6b3ac9c5a042 1774 MACC_PRINTF("DEV_STATUS_REQ ");
Wayne Roberts 0:6b3ac9c5a042 1775 {
Wayne Roberts 0:6b3ac9c5a042 1776 uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
Wayne Roberts 0:6b3ac9c5a042 1777 if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) )
Wayne Roberts 0:6b3ac9c5a042 1778 {
Wayne Roberts 0:6b3ac9c5a042 1779 batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
Wayne Roberts 0:6b3ac9c5a042 1780 }
Wayne Roberts 0:6b3ac9c5a042 1781 AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
Wayne Roberts 0:6b3ac9c5a042 1782 break;
Wayne Roberts 0:6b3ac9c5a042 1783 }
Wayne Roberts 0:6b3ac9c5a042 1784 case SRV_MAC_NEW_CHANNEL_REQ:
Wayne Roberts 0:6b3ac9c5a042 1785 {
Wayne Roberts 0:6b3ac9c5a042 1786 uint8_t status = 0x03;
Wayne Roberts 0:6b3ac9c5a042 1787
Wayne Roberts 0:6b3ac9c5a042 1788 #if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1789 status &= 0xFC; // Channel frequency and datarate KO
Wayne Roberts 0:6b3ac9c5a042 1790 macIndex += 5;
Wayne Roberts 0:6b3ac9c5a042 1791 #else
Wayne Roberts 0:6b3ac9c5a042 1792 int8_t channelIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 1793 ChannelParams_t chParam;
Wayne Roberts 0:6b3ac9c5a042 1794
Wayne Roberts 0:6b3ac9c5a042 1795 channelIndex = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1796 chParam.FreqHz = ( uint32_t )payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1797 chParam.FreqHz |= ( uint32_t )payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1798 chParam.FreqHz |= ( uint32_t )payload[macIndex++] << 16;
Wayne Roberts 0:6b3ac9c5a042 1799 chParam.FreqHz *= 100;
Wayne Roberts 0:6b3ac9c5a042 1800 chParam.DrRange.Value = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1801 MACC_PRINTF("NEW_CHANNEL_REQ ch%u %uhz drRange:%02x ", channelIndex, chParam.Frequency, chParam.DrRange.Value);
Wayne Roberts 0:6b3ac9c5a042 1802
Wayne Roberts 0:6b3ac9c5a042 1803 if( chParam.FreqHz == 0 )
Wayne Roberts 0:6b3ac9c5a042 1804 {
Wayne Roberts 0:6b3ac9c5a042 1805 if( channelIndex < 3 )
Wayne Roberts 0:6b3ac9c5a042 1806 {
Wayne Roberts 0:6b3ac9c5a042 1807 status &= 0xFC;
Wayne Roberts 0:6b3ac9c5a042 1808 }
Wayne Roberts 0:6b3ac9c5a042 1809 else
Wayne Roberts 0:6b3ac9c5a042 1810 {
Wayne Roberts 0:6b3ac9c5a042 1811 if( LoRaMacChannelRemove( channelIndex ) != LORAMAC_STATUS_OK )
Wayne Roberts 0:6b3ac9c5a042 1812 {
Wayne Roberts 0:6b3ac9c5a042 1813 status &= 0xFC;
Wayne Roberts 0:6b3ac9c5a042 1814 }
Wayne Roberts 0:6b3ac9c5a042 1815 }
Wayne Roberts 0:6b3ac9c5a042 1816 }
Wayne Roberts 0:6b3ac9c5a042 1817 else
Wayne Roberts 0:6b3ac9c5a042 1818 {
Wayne Roberts 0:6b3ac9c5a042 1819 switch( LoRaMacChannelAdd( channelIndex, chParam ) )
Wayne Roberts 0:6b3ac9c5a042 1820 {
Wayne Roberts 0:6b3ac9c5a042 1821 case LORAMAC_STATUS_OK:
Wayne Roberts 0:6b3ac9c5a042 1822 {
Wayne Roberts 0:6b3ac9c5a042 1823 MACC_PRINTF("add-ok ");
Wayne Roberts 0:6b3ac9c5a042 1824 break;
Wayne Roberts 0:6b3ac9c5a042 1825 }
Wayne Roberts 0:6b3ac9c5a042 1826 case LORAMAC_STATUS_FREQUENCY_INVALID:
Wayne Roberts 0:6b3ac9c5a042 1827 {
Wayne Roberts 0:6b3ac9c5a042 1828 MACC_PRINTF("add-bad-freq ");
Wayne Roberts 0:6b3ac9c5a042 1829 status &= 0xFE;
Wayne Roberts 0:6b3ac9c5a042 1830 break;
Wayne Roberts 0:6b3ac9c5a042 1831 }
Wayne Roberts 0:6b3ac9c5a042 1832 case LORAMAC_STATUS_DATARATE_INVALID:
Wayne Roberts 0:6b3ac9c5a042 1833 {
Wayne Roberts 0:6b3ac9c5a042 1834 MACC_PRINTF("add-bad-dr ");
Wayne Roberts 0:6b3ac9c5a042 1835 status &= 0xFD;
Wayne Roberts 0:6b3ac9c5a042 1836 break;
Wayne Roberts 0:6b3ac9c5a042 1837 }
Wayne Roberts 0:6b3ac9c5a042 1838 case LORAMAC_STATUS_FREQ_AND_DR_INVALID:
Wayne Roberts 0:6b3ac9c5a042 1839 {
Wayne Roberts 0:6b3ac9c5a042 1840 MACC_PRINTF("add-bad-both ");
Wayne Roberts 0:6b3ac9c5a042 1841 status &= 0xFC;
Wayne Roberts 0:6b3ac9c5a042 1842 break;
Wayne Roberts 0:6b3ac9c5a042 1843 }
Wayne Roberts 0:6b3ac9c5a042 1844 default:
Wayne Roberts 0:6b3ac9c5a042 1845 {
Wayne Roberts 0:6b3ac9c5a042 1846 MACC_PRINTF("add-bad-? ");
Wayne Roberts 0:6b3ac9c5a042 1847 status &= 0xFC;
Wayne Roberts 0:6b3ac9c5a042 1848 break;
Wayne Roberts 0:6b3ac9c5a042 1849 }
Wayne Roberts 0:6b3ac9c5a042 1850 }
Wayne Roberts 0:6b3ac9c5a042 1851 }
Wayne Roberts 0:6b3ac9c5a042 1852 #endif
Wayne Roberts 0:6b3ac9c5a042 1853 MACC_PRINTF("status:%x ", status);
Wayne Roberts 0:6b3ac9c5a042 1854 AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
Wayne Roberts 0:6b3ac9c5a042 1855 }
Wayne Roberts 0:6b3ac9c5a042 1856 break;
Wayne Roberts 3:eb174e10afbb 1857 case SRV_MAC_ADR_PARAM_SETUP_REQ:
Wayne Roberts 3:eb174e10afbb 1858 MACC_PRINTF("ADR_PARAM_SETUP_REQ");
Wayne Roberts 3:eb174e10afbb 1859 {
Wayne Roberts 3:eb174e10afbb 1860 uint8_t exps = payload[macIndex++] & 0x0F;
Wayne Roberts 3:eb174e10afbb 1861 ADR_ACK_LIMIT = 1 << (exps >> 4);
Wayne Roberts 3:eb174e10afbb 1862 ADR_ACK_DELAY = 1 << (exps & 0x0f);
Wayne Roberts 3:eb174e10afbb 1863 }
Wayne Roberts 3:eb174e10afbb 1864 AddMacCommand(SRV_MAC_ADR_PARAM_SETUP_ANS, 0, 0);
Wayne Roberts 3:eb174e10afbb 1865 break;
Wayne Roberts 0:6b3ac9c5a042 1866 case SRV_MAC_RX_TIMING_SETUP_REQ:
Wayne Roberts 0:6b3ac9c5a042 1867 MACC_PRINTF("RX_TIMING_SETUP_REQ");
Wayne Roberts 0:6b3ac9c5a042 1868 {
Wayne Roberts 0:6b3ac9c5a042 1869 uint8_t delay = payload[macIndex++] & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 1870
Wayne Roberts 0:6b3ac9c5a042 1871 if( delay == 0 )
Wayne Roberts 0:6b3ac9c5a042 1872 {
Wayne Roberts 0:6b3ac9c5a042 1873 delay++;
Wayne Roberts 0:6b3ac9c5a042 1874 }
Wayne Roberts 0:6b3ac9c5a042 1875 LoRaMacParams.ReceiveDelay1_us = delay * 1e6;
Wayne Roberts 0:6b3ac9c5a042 1876 LoRaMacParams.ReceiveDelay2_us = LoRaMacParams.ReceiveDelay1_us + 1e6;
Wayne Roberts 0:6b3ac9c5a042 1877 AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
Wayne Roberts 0:6b3ac9c5a042 1878 }
Wayne Roberts 0:6b3ac9c5a042 1879 break;
Wayne Roberts 0:6b3ac9c5a042 1880 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1881 case SRV_MAC_REKEY_CONF:
Wayne Roberts 3:eb174e10afbb 1882 macIndex++; //TODO server_version = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1883
Wayne Roberts 0:6b3ac9c5a042 1884 flags.need_ReKeyConf = 0;
Wayne Roberts 0:6b3ac9c5a042 1885 break;
Wayne Roberts 0:6b3ac9c5a042 1886 case SRV_MAC_FORCE_REJOIN_REQ:
Wayne Roberts 0:6b3ac9c5a042 1887 {
Wayne Roberts 0:6b3ac9c5a042 1888 uint16_t cmd_payload = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1889 cmd_payload |= payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1890 rejoin.type = (cmd_payload >> 4) & 7;
Wayne Roberts 0:6b3ac9c5a042 1891 if (rejoin.type == 2)
Wayne Roberts 0:6b3ac9c5a042 1892 JoinReqType = 2;
Wayne Roberts 0:6b3ac9c5a042 1893 else {
Wayne Roberts 0:6b3ac9c5a042 1894 JoinReqType = 0;
Wayne Roberts 0:6b3ac9c5a042 1895 rejoin.type = 0;
Wayne Roberts 0:6b3ac9c5a042 1896 }
Wayne Roberts 0:6b3ac9c5a042 1897
Wayne Roberts 0:6b3ac9c5a042 1898 rejoin.dr = cmd_payload & 0x0f;
Wayne Roberts 0:6b3ac9c5a042 1899 LoRaMacParams.ChannelsDatarate = rejoin.dr;
Wayne Roberts 0:6b3ac9c5a042 1900 rejoin.retries = 1 + ((cmd_payload >> 8) & 7);
Wayne Roberts 0:6b3ac9c5a042 1901 MAC_PRINTF("FORCE_REJOIN 0x%04x dr%u type%u tries%u ", cmd_payload, LoRaMacParams.ChannelsDatarate, JoinReqType, rejoin.retries);
Wayne Roberts 0:6b3ac9c5a042 1902
Wayne Roberts 0:6b3ac9c5a042 1903 {
Wayne Roberts 0:6b3ac9c5a042 1904 rejoin.Period = (cmd_payload >> 11) & 7;
Wayne Roberts 0:6b3ac9c5a042 1905 /* first forced-rejoin attempt must be immediate */
Wayne Roberts 0:6b3ac9c5a042 1906 rejoin.event.attach_us(_rejoin_retry, 50000);
Wayne Roberts 0:6b3ac9c5a042 1907 rejoin.forced = true;
Wayne Roberts 0:6b3ac9c5a042 1908 }
Wayne Roberts 0:6b3ac9c5a042 1909 }
Wayne Roberts 0:6b3ac9c5a042 1910 break;
Wayne Roberts 0:6b3ac9c5a042 1911 case SRV_MAC_REJOIN_PARAM_REQ:
Wayne Roberts 0:6b3ac9c5a042 1912 {
Wayne Roberts 0:6b3ac9c5a042 1913 uint8_t p = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1914 rejoin.type0.MaxTimeN = p >> 4;
Wayne Roberts 0:6b3ac9c5a042 1915 rejoin.type0.MaxCountN = p & 0xf;
Wayne Roberts 0:6b3ac9c5a042 1916 rejoin.type0.enabled = true;
Wayne Roberts 0:6b3ac9c5a042 1917 MACC_PRINTF("REJOIN_PARAM MaxTimeN%u MaxCountN%u ", rejoin.type0.MaxTimeN, rejoin.type0.MaxCountN);
Wayne Roberts 0:6b3ac9c5a042 1918 rejoin.type0.uplinks_since = 1 << (rejoin.type0.MaxCountN + 4);
Wayne Roberts 0:6b3ac9c5a042 1919 AddMacCommand(MOTE_MAC_REJOIN_PARAM_ANS, 0, 0);
Wayne Roberts 0:6b3ac9c5a042 1920 }
Wayne Roberts 0:6b3ac9c5a042 1921 break;
Wayne Roberts 0:6b3ac9c5a042 1922 #else
Wayne Roberts 0:6b3ac9c5a042 1923 case SRV_MAC_RESET_CONF:
Wayne Roberts 0:6b3ac9c5a042 1924 macIndex++; //TODO server_version = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1925 flags.need_ResetConf = 0;
Wayne Roberts 0:6b3ac9c5a042 1926 break;
Wayne Roberts 0:6b3ac9c5a042 1927 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1928 case SRV_MAC_DEVICE_TIME_ANS:
Wayne Roberts 0:6b3ac9c5a042 1929 {
Wayne Roberts 0:6b3ac9c5a042 1930 uint32_t subusecs, secs;
Wayne Roberts 0:6b3ac9c5a042 1931 us_timestamp_t us_since_tx_done;
Wayne Roberts 0:6b3ac9c5a042 1932 secs = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1933 secs += payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1934 secs += payload[macIndex++] << 16;
Wayne Roberts 0:6b3ac9c5a042 1935 secs += payload[macIndex++] << 24;
Wayne Roberts 0:6b3ac9c5a042 1936 subusecs = payload[macIndex++] * 3906.5;
Wayne Roberts 0:6b3ac9c5a042 1937
Wayne Roberts 0:6b3ac9c5a042 1938 //MAC_PRINTF("secs:%u, subusecs:%u\r\n", secs, subusecs);
Wayne Roberts 0:6b3ac9c5a042 1939 deviceTimeClassB(secs, subusecs);
Wayne Roberts 0:6b3ac9c5a042 1940
Wayne Roberts 0:6b3ac9c5a042 1941 us_since_tx_done = Radio::lpt.read_us() - tx_done_at;
Wayne Roberts 0:6b3ac9c5a042 1942 MlmeConfirm.fields.time.uSeconds += us_since_tx_done;
Wayne Roberts 0:6b3ac9c5a042 1943 while (us_since_tx_done >= 1000000) {
Wayne Roberts 0:6b3ac9c5a042 1944 MlmeConfirm.fields.time.Seconds++;
Wayne Roberts 0:6b3ac9c5a042 1945 us_since_tx_done -= 1000000;
Wayne Roberts 0:6b3ac9c5a042 1946 }
Wayne Roberts 0:6b3ac9c5a042 1947 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1948 MlmeConfirm.fields.time.Seconds = secs;
Wayne Roberts 0:6b3ac9c5a042 1949 MlmeConfirm.fields.time.uSeconds = subusecs;
Wayne Roberts 0:6b3ac9c5a042 1950 }
Wayne Roberts 0:6b3ac9c5a042 1951 break;
Wayne Roberts 0:6b3ac9c5a042 1952 default:
Wayne Roberts 0:6b3ac9c5a042 1953 --macIndex;
Wayne Roberts 0:6b3ac9c5a042 1954 if (ProcessMacCommandsClassB(payload, &macIndex)) {
Wayne Roberts 0:6b3ac9c5a042 1955 /* mac command was taken */
Wayne Roberts 0:6b3ac9c5a042 1956 //MACC_PRINTF("B-cont\r\n");
Wayne Roberts 0:6b3ac9c5a042 1957 }
Wayne Roberts 0:6b3ac9c5a042 1958 #ifdef DUTY_ENABLE
Wayne Roberts 0:6b3ac9c5a042 1959 else if (ProcessMacCommandsDuty(payload, &macIndex)) {
Wayne Roberts 0:6b3ac9c5a042 1960 /* mac command was taken */
Wayne Roberts 0:6b3ac9c5a042 1961 }
Wayne Roberts 0:6b3ac9c5a042 1962 #endif /* DUTY_ENABLE */
Wayne Roberts 0:6b3ac9c5a042 1963 else {
Wayne Roberts 0:6b3ac9c5a042 1964 ret = -1;
Wayne Roberts 0:6b3ac9c5a042 1965 MAC_PRINTF("unknown mac:0x%02x at %u\r\n", payload[macIndex-1], macIndex-1);
Wayne Roberts 0:6b3ac9c5a042 1966 }
Wayne Roberts 0:6b3ac9c5a042 1967 break;
Wayne Roberts 0:6b3ac9c5a042 1968 } // ..switch(payload[macIndex++])
Wayne Roberts 0:6b3ac9c5a042 1969
Wayne Roberts 0:6b3ac9c5a042 1970 MACC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 1971
Wayne Roberts 0:6b3ac9c5a042 1972 } // ..while( macIndex < commandsSize )
Wayne Roberts 0:6b3ac9c5a042 1973
Wayne Roberts 0:6b3ac9c5a042 1974 return ret;
Wayne Roberts 0:6b3ac9c5a042 1975 } // ..ProcessMacCommands()
Wayne Roberts 0:6b3ac9c5a042 1976
Wayne Roberts 0:6b3ac9c5a042 1977 #define MAX_FCNT_GAP 0x4000
Wayne Roberts 0:6b3ac9c5a042 1978 /* return: true == send downlink ack */
Wayne Roberts 0:6b3ac9c5a042 1979 static int
Wayne Roberts 0:6b3ac9c5a042 1980 rx_downlink(uint8_t pktHeaderLen, uint8_t* rx_payload, uint16_t rx_size, int8_t snr, us_timestamp_t us_rxDone_at)
Wayne Roberts 0:6b3ac9c5a042 1981 {
Wayne Roberts 0:6b3ac9c5a042 1982 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 1983 LoRaMacFrameCtrl_t fCtrl;
Wayne Roberts 0:6b3ac9c5a042 1984 uint32_t myFCntDwn32, rxFCnt32;
Wayne Roberts 0:6b3ac9c5a042 1985 uint8_t rxFPort;
Wayne Roberts 0:6b3ac9c5a042 1986 uint16_t rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 1987 uint32_t address;
Wayne Roberts 0:6b3ac9c5a042 1988 uint32_t mic, micRx;
Wayne Roberts 0:6b3ac9c5a042 1989 uint8_t appPayloadStartIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 1990 bool skipIndication = false;
Wayne Roberts 0:6b3ac9c5a042 1991 uint8_t frameLen = 0;
Wayne Roberts 0:6b3ac9c5a042 1992 bool is_AFCntDown;
Wayne Roberts 0:6b3ac9c5a042 1993 block_t block;
Wayne Roberts 0:6b3ac9c5a042 1994
Wayne Roberts 0:6b3ac9c5a042 1995 macHdr.Value = rx_payload[0];
Wayne Roberts 0:6b3ac9c5a042 1996
Wayne Roberts 0:6b3ac9c5a042 1997 address = rx_payload[pktHeaderLen++];
Wayne Roberts 0:6b3ac9c5a042 1998 address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 8 );
Wayne Roberts 0:6b3ac9c5a042 1999 address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 16 );
Wayne Roberts 0:6b3ac9c5a042 2000 address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 24 );
Wayne Roberts 0:6b3ac9c5a042 2001
Wayne Roberts 0:6b3ac9c5a042 2002 fCtrl.Value = rx_payload[pktHeaderLen++];
Wayne Roberts 0:6b3ac9c5a042 2003
Wayne Roberts 0:6b3ac9c5a042 2004 rxFCnt16 = ( uint16_t )rx_payload[pktHeaderLen++];
Wayne Roberts 0:6b3ac9c5a042 2005 rxFCnt16 |= ( uint16_t )rx_payload[pktHeaderLen++] << 8;
Wayne Roberts 0:6b3ac9c5a042 2006
Wayne Roberts 0:6b3ac9c5a042 2007 is_AFCntDown = false;
Wayne Roberts 0:6b3ac9c5a042 2008 if (( ( rx_size - 4 ) - (8 + fCtrl.Bits.FOptsLen) ) > 0) {
Wayne Roberts 0:6b3ac9c5a042 2009 appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
Wayne Roberts 0:6b3ac9c5a042 2010 rxFPort = rx_payload[appPayloadStartIndex++];
Wayne Roberts 0:6b3ac9c5a042 2011 if (flags.OptNeg && rxFPort > 0)
Wayne Roberts 0:6b3ac9c5a042 2012 is_AFCntDown = true;
Wayne Roberts 0:6b3ac9c5a042 2013 } /* else no payload/fport present */
Wayne Roberts 0:6b3ac9c5a042 2014
Wayne Roberts 0:6b3ac9c5a042 2015 myFCntDwn32 = get_fcntdwn(is_AFCntDown);
Wayne Roberts 0:6b3ac9c5a042 2016
Wayne Roberts 0:6b3ac9c5a042 2017 McpsIndication.expectedFCntDown = myFCntDwn32;
Wayne Roberts 0:6b3ac9c5a042 2018 McpsIndication.receivedFCntDown = rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 2019
Wayne Roberts 0:6b3ac9c5a042 2020 rxFCnt32 = (myFCntDwn32 & 0xffff0000) | rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 2021 DEBUG_MIC_DOWN(" rxFCnt32:%" PRIu32" ", rxFCnt32);
Wayne Roberts 0:6b3ac9c5a042 2022
Wayne Roberts 0:6b3ac9c5a042 2023 micRx = ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN];
Wayne Roberts 0:6b3ac9c5a042 2024 micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 1] << 8 );
Wayne Roberts 0:6b3ac9c5a042 2025 micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 2] << 16 );
Wayne Roberts 0:6b3ac9c5a042 2026 micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 3] << 24 );
Wayne Roberts 0:6b3ac9c5a042 2027
Wayne Roberts 0:6b3ac9c5a042 2028 block.b.header = 0x49;
Wayne Roberts 0:6b3ac9c5a042 2029 if (flags.OptNeg)
Wayne Roberts 0:6b3ac9c5a042 2030 block.b.confFCnt = ConfFCntUp;
Wayne Roberts 0:6b3ac9c5a042 2031 else
Wayne Roberts 0:6b3ac9c5a042 2032 block.b.confFCnt = 0;
Wayne Roberts 0:6b3ac9c5a042 2033 block.b.dr = 0;
Wayne Roberts 0:6b3ac9c5a042 2034 block.b.ch = 0;
Wayne Roberts 0:6b3ac9c5a042 2035 block.b.dir = DOWN_LINK;
Wayne Roberts 0:6b3ac9c5a042 2036 block.b.DevAddr = address;
Wayne Roberts 0:6b3ac9c5a042 2037 block.b.FCnt = rxFCnt32;
Wayne Roberts 0:6b3ac9c5a042 2038 block.b.zero8 = 0;
Wayne Roberts 0:6b3ac9c5a042 2039 block.b.lenMsg = rx_size - LORAMAC_MFR_LEN;
Wayne Roberts 0:6b3ac9c5a042 2040 mic = LoRaMacComputeMic(&block, rx_payload, keys.SNwkSIntKey);
Wayne Roberts 0:6b3ac9c5a042 2041 if (micRx != mic) {
Wayne Roberts 0:6b3ac9c5a042 2042 bool ignore_rx = true;
Wayne Roberts 3:eb174e10afbb 2043 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_MIC_FAIL);
Wayne Roberts 0:6b3ac9c5a042 2044 MAC_PRINTF("\e[31mmicFail");
Wayne Roberts 0:6b3ac9c5a042 2045 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2046 block.b.confFCnt = ConfFCntUp - 1;
Wayne Roberts 0:6b3ac9c5a042 2047 mic = LoRaMacComputeMic(&block, rx_payload, keys.SNwkSIntKey);
Wayne Roberts 3:eb174e10afbb 2048 if (micRx == mic)
Wayne Roberts 0:6b3ac9c5a042 2049 ignore_rx = false;
Wayne Roberts 3:eb174e10afbb 2050 else {
Wayne Roberts 0:6b3ac9c5a042 2051 block.b.confFCnt = 0;
Wayne Roberts 0:6b3ac9c5a042 2052 mic = LoRaMacComputeMic(&block, rx_payload, keys.SNwkSIntKey);
Wayne Roberts 3:eb174e10afbb 2053 if (micRx == mic)
Wayne Roberts 0:6b3ac9c5a042 2054 ignore_rx = false;
Wayne Roberts 0:6b3ac9c5a042 2055 }
Wayne Roberts 0:6b3ac9c5a042 2056 }
Wayne Roberts 0:6b3ac9c5a042 2057 if (ignore_rx) {
Wayne Roberts 0:6b3ac9c5a042 2058 MAC_PRINTF("\e[0m\r\n");
Wayne Roberts 0:6b3ac9c5a042 2059 return -1;
Wayne Roberts 0:6b3ac9c5a042 2060 } else {
Wayne Roberts 0:6b3ac9c5a042 2061 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
Wayne Roberts 0:6b3ac9c5a042 2062 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 2063 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
Wayne Roberts 0:6b3ac9c5a042 2064 }
Wayne Roberts 0:6b3ac9c5a042 2065 } else {
Wayne Roberts 0:6b3ac9c5a042 2066 /* downlink with good MIC means previous confirmed uplink was receied */
Wayne Roberts 0:6b3ac9c5a042 2067 ConfFCntUp = 0;
Wayne Roberts 7:4b6f960dcca2 2068 if (McpsIndication.RxSlot == 1) { // no need for RX2 with good mic on rx1
Wayne Roberts 0:6b3ac9c5a042 2069 RxWindowEvent2.detach();
Wayne Roberts 7:4b6f960dcca2 2070 }
Wayne Roberts 0:6b3ac9c5a042 2071 }
Wayne Roberts 0:6b3ac9c5a042 2072
Wayne Roberts 0:6b3ac9c5a042 2073 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2074 //McpsIndication.Multicast = 0;//multicast;
Wayne Roberts 0:6b3ac9c5a042 2075 McpsIndication.FramePending = fCtrl.Bits.FPending;
Wayne Roberts 0:6b3ac9c5a042 2076 McpsIndication.Buffer = NULL;
Wayne Roberts 0:6b3ac9c5a042 2077 McpsIndication.BufferSize = 0;
Wayne Roberts 0:6b3ac9c5a042 2078
Wayne Roberts 0:6b3ac9c5a042 2079 MacCommandsBufferToRepeatIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 2080
Wayne Roberts 0:6b3ac9c5a042 2081 if (macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN)
Wayne Roberts 0:6b3ac9c5a042 2082 {
Wayne Roberts 0:6b3ac9c5a042 2083 flags.SrvAckRequested = true;
Wayne Roberts 0:6b3ac9c5a042 2084 McpsIndication.McpsIndication = MCPS_CONFIRMED;
Wayne Roberts 0:6b3ac9c5a042 2085
Wayne Roberts 0:6b3ac9c5a042 2086 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2087 if (flags.IsLoRaMacNetworkJoined)
Wayne Roberts 0:6b3ac9c5a042 2088 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2089
Wayne Roberts 0:6b3ac9c5a042 2090 if (flags.OptNeg)
Wayne Roberts 0:6b3ac9c5a042 2091 ConfFCntDown = rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 2092 }
Wayne Roberts 0:6b3ac9c5a042 2093 else
Wayne Roberts 0:6b3ac9c5a042 2094 { // FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
Wayne Roberts 0:6b3ac9c5a042 2095 ConfFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 2096 flags.SrvAckRequested = false;
Wayne Roberts 0:6b3ac9c5a042 2097 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
Wayne Roberts 0:6b3ac9c5a042 2098 }
Wayne Roberts 0:6b3ac9c5a042 2099
Wayne Roberts 0:6b3ac9c5a042 2100 if (fCtrl.Bits.FOptsLen > 0)
Wayne Roberts 0:6b3ac9c5a042 2101 {
Wayne Roberts 0:6b3ac9c5a042 2102 // Decode Options field MAC commands
Wayne Roberts 0:6b3ac9c5a042 2103 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2104 uint32_t FCnt32;
Wayne Roberts 0:6b3ac9c5a042 2105 bool fromStored;
Wayne Roberts 0:6b3ac9c5a042 2106 uint8_t macDecrypt[16];
Wayne Roberts 0:6b3ac9c5a042 2107 DEBUG_CRYPT_BUF(keys.NwkSEncKey, 16, "NwkSEncKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2108 if (appPayloadStartIndex > 0) {
Wayne Roberts 0:6b3ac9c5a042 2109 /* rx header has AFCntDown: not for use with FOpts */
Wayne Roberts 0:6b3ac9c5a042 2110 FCnt32 = get_fcntdwn(false);
Wayne Roberts 0:6b3ac9c5a042 2111 fromStored = true;
Wayne Roberts 0:6b3ac9c5a042 2112 } else {
Wayne Roberts 0:6b3ac9c5a042 2113 /* NFCntDown received in rx header */
Wayne Roberts 0:6b3ac9c5a042 2114 FCnt32 = (get_fcntdwn(false) & 0xffff0000) | rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 2115 fromStored = false;
Wayne Roberts 0:6b3ac9c5a042 2116 }
Wayne Roberts 0:6b3ac9c5a042 2117 DEBUG_CRYPT("FCnt32:%" PRIu32" ", FCnt32);
Wayne Roberts 0:6b3ac9c5a042 2118 DEBUG_CRYPT_BUF(rx_payload+8, fCtrl.Bits.FOptsLen, "FOpts-rx", 0);
Wayne Roberts 0:6b3ac9c5a042 2119 LoRaMacEncrypt(0, rx_payload+8, fCtrl.Bits.FOptsLen, keys.NwkSEncKey, LoRaMacDevAddr, DOWN_LINK, FCnt32, macDecrypt);
Wayne Roberts 0:6b3ac9c5a042 2120 DEBUG_CRYPT_BUF(macDecrypt, fCtrl.Bits.FOptsLen, "FOpts-decrypt", 0);
Wayne Roberts 0:6b3ac9c5a042 2121 if (ProcessMacCommands(macDecrypt, 0, fCtrl.Bits.FOptsLen, snr, us_rxDone_at) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2122 if (fromStored) {
Wayne Roberts 0:6b3ac9c5a042 2123 MAC_PRINTF("fromStored-");
Wayne Roberts 0:6b3ac9c5a042 2124 }
Wayne Roberts 0:6b3ac9c5a042 2125 MAC_PRINTF("FCnt32:%lu ", FCnt32);
Wayne Roberts 0:6b3ac9c5a042 2126 }
Wayne Roberts 0:6b3ac9c5a042 2127 } else {
Wayne Roberts 0:6b3ac9c5a042 2128 MAC_PRINTF("ProcessMacCommands-FOpts ");
Wayne Roberts 0:6b3ac9c5a042 2129 ProcessMacCommands( rx_payload, 8, fCtrl.Bits.FOptsLen + 8, snr, us_rxDone_at );
Wayne Roberts 0:6b3ac9c5a042 2130 }
Wayne Roberts 0:6b3ac9c5a042 2131 }
Wayne Roberts 0:6b3ac9c5a042 2132
Wayne Roberts 0:6b3ac9c5a042 2133 if (appPayloadStartIndex > 0)
Wayne Roberts 0:6b3ac9c5a042 2134 {
Wayne Roberts 0:6b3ac9c5a042 2135 frameLen = ( rx_size - 4 ) - appPayloadStartIndex;
Wayne Roberts 0:6b3ac9c5a042 2136
Wayne Roberts 0:6b3ac9c5a042 2137 McpsIndication.Port = rxFPort;
Wayne Roberts 0:6b3ac9c5a042 2138
Wayne Roberts 0:6b3ac9c5a042 2139 if (rxFPort == 0)
Wayne Roberts 0:6b3ac9c5a042 2140 {
Wayne Roberts 0:6b3ac9c5a042 2141 if( ( fCtrl.Bits.FOptsLen == 0 ) /*&& ( multicast == 0 )*/ )
Wayne Roberts 0:6b3ac9c5a042 2142 {
Wayne Roberts 0:6b3ac9c5a042 2143 uint8_t macDecrypt[16];
Wayne Roberts 0:6b3ac9c5a042 2144 LoRaMacPayloadDecrypt(rx_payload + appPayloadStartIndex,
Wayne Roberts 0:6b3ac9c5a042 2145 frameLen,
Wayne Roberts 0:6b3ac9c5a042 2146 keys.NwkSEncKey,
Wayne Roberts 0:6b3ac9c5a042 2147 address,
Wayne Roberts 0:6b3ac9c5a042 2148 DOWN_LINK,
Wayne Roberts 0:6b3ac9c5a042 2149 rxFCnt32,
Wayne Roberts 0:6b3ac9c5a042 2150 macDecrypt
Wayne Roberts 0:6b3ac9c5a042 2151 );
Wayne Roberts 0:6b3ac9c5a042 2152
Wayne Roberts 0:6b3ac9c5a042 2153 // Decode frame payload MAC commands
Wayne Roberts 0:6b3ac9c5a042 2154 MAC_PRINTF("ProcessMacCommands-payload ");
Wayne Roberts 0:6b3ac9c5a042 2155 if (ProcessMacCommands( macDecrypt, 0, frameLen, snr, us_rxDone_at ) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2156 MAC_PRINTF(" rxFCnt32:%" PRIu32 " ", rxFCnt32);
Wayne Roberts 0:6b3ac9c5a042 2157 }
Wayne Roberts 0:6b3ac9c5a042 2158 }
Wayne Roberts 0:6b3ac9c5a042 2159 else
Wayne Roberts 0:6b3ac9c5a042 2160 {
Wayne Roberts 0:6b3ac9c5a042 2161 skipIndication = true;
Wayne Roberts 0:6b3ac9c5a042 2162 }
Wayne Roberts 0:6b3ac9c5a042 2163 }
Wayne Roberts 0:6b3ac9c5a042 2164 else
Wayne Roberts 0:6b3ac9c5a042 2165 { /* rxFPort > 0 */
Wayne Roberts 0:6b3ac9c5a042 2166 MAC_PRINTF("rxFCnt32:%" PRIu32" %08" PRIx32" ", rxFCnt32, address);
Wayne Roberts 0:6b3ac9c5a042 2167 MAC_PRINTF("FCntDown%" PRIu32 " ", rxFCnt32);
Wayne Roberts 0:6b3ac9c5a042 2168 DEBUG_CRYPT(" addr%" PRIx32" len%u\r\n", address, frameLen);
Wayne Roberts 0:6b3ac9c5a042 2169 DEBUG_CRYPT_BUF(rx_payload + appPayloadStartIndex, frameLen, "rxEncd", 0);
Wayne Roberts 0:6b3ac9c5a042 2170 DEBUG_CRYPT_BUF(keys.AppSKey, 16, "AppSKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2171 LoRaMacPayloadDecrypt(rx_payload + appPayloadStartIndex,
Wayne Roberts 0:6b3ac9c5a042 2172 frameLen,
Wayne Roberts 0:6b3ac9c5a042 2173 keys.AppSKey,
Wayne Roberts 0:6b3ac9c5a042 2174 address,
Wayne Roberts 0:6b3ac9c5a042 2175 DOWN_LINK,
Wayne Roberts 0:6b3ac9c5a042 2176 rxFCnt32,
Wayne Roberts 0:6b3ac9c5a042 2177 rxFRMPayload
Wayne Roberts 0:6b3ac9c5a042 2178 );
Wayne Roberts 0:6b3ac9c5a042 2179
Wayne Roberts 0:6b3ac9c5a042 2180 if( skipIndication == false )
Wayne Roberts 0:6b3ac9c5a042 2181 {
Wayne Roberts 0:6b3ac9c5a042 2182 McpsIndication.Buffer = rxFRMPayload;
Wayne Roberts 0:6b3ac9c5a042 2183 McpsIndication.BufferSize = frameLen;
Wayne Roberts 0:6b3ac9c5a042 2184 McpsIndication.RxData = true;
Wayne Roberts 0:6b3ac9c5a042 2185 }
Wayne Roberts 0:6b3ac9c5a042 2186 }
Wayne Roberts 0:6b3ac9c5a042 2187 } // ..if have payload
Wayne Roberts 0:6b3ac9c5a042 2188
Wayne Roberts 3:eb174e10afbb 2189 if (!skipIndication)
Wayne Roberts 0:6b3ac9c5a042 2190 {
Wayne Roberts 3:eb174e10afbb 2191 McpsIndication.AckReceived = fCtrl.Bits.Ack;
Wayne Roberts 3:eb174e10afbb 2192 McpsConfirm.AckReceived = fCtrl.Bits.Ack;
Wayne Roberts 0:6b3ac9c5a042 2193
Wayne Roberts 0:6b3ac9c5a042 2194 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 2195 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); // RxDone
Wayne Roberts 0:6b3ac9c5a042 2196 }
Wayne Roberts 0:6b3ac9c5a042 2197
Wayne Roberts 3:eb174e10afbb 2198 if (McpsIndication.RxSlot == 1 || McpsIndication.RxSlot == 2)
Wayne Roberts 3:eb174e10afbb 2199 McpsIndication.ADR_ACK_CNT = 0;
Wayne Roberts 3:eb174e10afbb 2200
Wayne Roberts 3:eb174e10afbb 2201 /* set FCntDwn to next expected value, if last NbTrans */
Wayne Roberts 0:6b3ac9c5a042 2202 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 3:eb174e10afbb 2203 if (flags.uplink_in_progress <= 1 && last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_UP) {
Wayne Roberts 0:6b3ac9c5a042 2204 if (fCtrl.Bits.Ack) {
Wayne Roberts 0:6b3ac9c5a042 2205 FCntUp++;
Wayne Roberts 0:6b3ac9c5a042 2206 } else {
Wayne Roberts 0:6b3ac9c5a042 2207 MAC_PRINTF("\e[31mrx-!ack\e[0m\n");
Wayne Roberts 0:6b3ac9c5a042 2208 }
Wayne Roberts 0:6b3ac9c5a042 2209 }
Wayne Roberts 0:6b3ac9c5a042 2210
Wayne Roberts 0:6b3ac9c5a042 2211 if (is_AFCntDown) {
Wayne Roberts 0:6b3ac9c5a042 2212 AFCntDown = rxFCnt32 + 1;
Wayne Roberts 0:6b3ac9c5a042 2213 } else {
Wayne Roberts 0:6b3ac9c5a042 2214 NFCntDown = rxFCnt32 + 1;
Wayne Roberts 0:6b3ac9c5a042 2215 }
Wayne Roberts 0:6b3ac9c5a042 2216 #else
Wayne Roberts 3:eb174e10afbb 2217 /* if last NbTrans confirmed uplink ack'd ok: increment FCntUp */
Wayne Roberts 3:eb174e10afbb 2218 if (flags.uplink_in_progress <= 1 && fCtrl.Bits.Ack && last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_UP) {
Wayne Roberts 0:6b3ac9c5a042 2219 eeprom_increment_value(EEPROM_FCNTUP); /* TODO handle ee-failure return */
Wayne Roberts 3:eb174e10afbb 2220 }
Wayne Roberts 0:6b3ac9c5a042 2221
Wayne Roberts 0:6b3ac9c5a042 2222 if (is_AFCntDown)
Wayne Roberts 0:6b3ac9c5a042 2223 eeprom_write_word(EEPROM_AFCNTDWN, rxFCnt32 + 1);
Wayne Roberts 0:6b3ac9c5a042 2224 else
Wayne Roberts 0:6b3ac9c5a042 2225 eeprom_write_word(EEPROM_NFCNTDWN, rxFCnt32 + 1);
Wayne Roberts 0:6b3ac9c5a042 2226 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2227
Wayne Roberts 0:6b3ac9c5a042 2228 return 0;
Wayne Roberts 0:6b3ac9c5a042 2229 } // ...rx_downlink()
Wayne Roberts 0:6b3ac9c5a042 2230
Wayne Roberts 0:6b3ac9c5a042 2231
Wayne Roberts 0:6b3ac9c5a042 2232 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2233 typedef union {
Wayne Roberts 0:6b3ac9c5a042 2234 struct {
Wayne Roberts 0:6b3ac9c5a042 2235 uint8_t mhdr;
Wayne Roberts 0:6b3ac9c5a042 2236 unsigned int joinNonce : 24;
Wayne Roberts 0:6b3ac9c5a042 2237 unsigned int Home_NetID : 24;
Wayne Roberts 0:6b3ac9c5a042 2238 uint32_t DevAddr;
Wayne Roberts 0:6b3ac9c5a042 2239 struct {
Wayne Roberts 0:6b3ac9c5a042 2240 uint8_t RX2dr : 4; // 0,1,2,3
Wayne Roberts 0:6b3ac9c5a042 2241 uint8_t RX1DRoffset : 3; // 4,5,6
Wayne Roberts 0:6b3ac9c5a042 2242 uint8_t OptNeg : 1; // 7
Wayne Roberts 0:6b3ac9c5a042 2243 } DLSettings;
Wayne Roberts 0:6b3ac9c5a042 2244 uint8_t RxDelay;
Wayne Roberts 0:6b3ac9c5a042 2245 } __attribute__((packed)) fields;
Wayne Roberts 0:6b3ac9c5a042 2246 uint8_t octets[13];
Wayne Roberts 0:6b3ac9c5a042 2247 } joinAccept_t;
Wayne Roberts 0:6b3ac9c5a042 2248 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2249
Wayne Roberts 0:6b3ac9c5a042 2250
Wayne Roberts 0:6b3ac9c5a042 2251 #define JOIN_ACCEPT_MAX_SIZE 34
Wayne Roberts 0:6b3ac9c5a042 2252 static void
Wayne Roberts 0:6b3ac9c5a042 2253 OnRadioRxDone(uint8_t *rx_payload, uint16_t rx_size, int16_t rssi, int8_t snr, us_timestamp_t us_rxDone_at)
Wayne Roberts 0:6b3ac9c5a042 2254 {
Wayne Roberts 0:6b3ac9c5a042 2255 LoRaMacEventInfoStatus_t status = LORAMAC_EVENT_INFO_STATUS_UNKNOWN_MTYPE;
Wayne Roberts 0:6b3ac9c5a042 2256 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 2257 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2258 uint8_t _jaDecrypted[JOIN_ACCEPT_MAX_SIZE];
Wayne Roberts 0:6b3ac9c5a042 2259 uint32_t mic, micRx;
Wayne Roberts 0:6b3ac9c5a042 2260 const uint8_t* key;
Wayne Roberts 0:6b3ac9c5a042 2261 const joinAccept_t* ja;
Wayne Roberts 0:6b3ac9c5a042 2262 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2263 uint8_t pktHeaderLen = 0;
Wayne Roberts 0:6b3ac9c5a042 2264
Wayne Roberts 0:6b3ac9c5a042 2265 McpsConfirm.AckReceived = false;
Wayne Roberts 0:6b3ac9c5a042 2266 McpsIndication.Rssi = rssi;
Wayne Roberts 0:6b3ac9c5a042 2267 McpsIndication.Snr = snr;
Wayne Roberts 0:6b3ac9c5a042 2268 McpsIndication.Port = 0;
Wayne Roberts 0:6b3ac9c5a042 2269 //McpsIndication.Multicast = 0;
Wayne Roberts 0:6b3ac9c5a042 2270 McpsIndication.FramePending = 0;
Wayne Roberts 0:6b3ac9c5a042 2271 McpsIndication.Buffer = NULL;
Wayne Roberts 0:6b3ac9c5a042 2272 McpsIndication.BufferSize = 0;
Wayne Roberts 0:6b3ac9c5a042 2273 McpsIndication.RxData = false;
Wayne Roberts 0:6b3ac9c5a042 2274 McpsIndication.AckReceived = false;
Wayne Roberts 0:6b3ac9c5a042 2275 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
Wayne Roberts 0:6b3ac9c5a042 2276
Wayne Roberts 0:6b3ac9c5a042 2277 if (MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_SENDING) {
Wayne Roberts 0:6b3ac9c5a042 2278 /* when regular downlink is sent in response to rejoin request */
Wayne Roberts 0:6b3ac9c5a042 2279 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2280 }
Wayne Roberts 0:6b3ac9c5a042 2281
Wayne Roberts 7:4b6f960dcca2 2282 if (LoRaMacDeviceClass != CLASS_C)
Wayne Roberts 0:6b3ac9c5a042 2283 {
Wayne Roberts 8:5a5ea7cc946f 2284 Radio::Sleep();
Wayne Roberts 0:6b3ac9c5a042 2285 }
Wayne Roberts 0:6b3ac9c5a042 2286
Wayne Roberts 0:6b3ac9c5a042 2287 MAC_PRINTF("OnRadioRxDone(%u) RxSlot%d ", rx_size, McpsIndication.RxSlot);
Wayne Roberts 0:6b3ac9c5a042 2288 if (beacon_rx_done_payload(rx_payload, rx_size))
Wayne Roberts 0:6b3ac9c5a042 2289 return;
Wayne Roberts 0:6b3ac9c5a042 2290
Wayne Roberts 0:6b3ac9c5a042 2291 macHdr.Value = rx_payload[pktHeaderLen++];
Wayne Roberts 0:6b3ac9c5a042 2292
Wayne Roberts 0:6b3ac9c5a042 2293 MAC_PRINTF(" rx-");
Wayne Roberts 0:6b3ac9c5a042 2294 print_mtype(macHdr.Bits.MType);
Wayne Roberts 0:6b3ac9c5a042 2295 switch (macHdr.Bits.MType)
Wayne Roberts 0:6b3ac9c5a042 2296 {
Wayne Roberts 0:6b3ac9c5a042 2297 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2298 case FRAME_TYPE_JOIN_ACCEPT:
Wayne Roberts 0:6b3ac9c5a042 2299 /* always permitting join accept because it might be due to rejoin */
Wayne Roberts 0:6b3ac9c5a042 2300 if (rx_size >= JOIN_ACCEPT_MAX_SIZE) {
Wayne Roberts 8:5a5ea7cc946f 2301 MAC_PRINTF("joinAccept overSize %u\r\n", rx_size);
Wayne Roberts 0:6b3ac9c5a042 2302 return;
Wayne Roberts 0:6b3ac9c5a042 2303 }
Wayne Roberts 0:6b3ac9c5a042 2304
Wayne Roberts 0:6b3ac9c5a042 2305 DEBUG_CRYPT_BUF(rx_payload, rx_size, "rxBuf", 0);
Wayne Roberts 0:6b3ac9c5a042 2306 MAC_PRINTF("JoinReqType:%02x ", JoinReqType);
Wayne Roberts 0:6b3ac9c5a042 2307 if (JoinReqType == 0xff) {
Wayne Roberts 0:6b3ac9c5a042 2308 DEBUG_CRYPT_BUF(RootNwkKey, 16, "NwkKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2309 key = RootNwkKey;
Wayne Roberts 0:6b3ac9c5a042 2310 } else {
Wayne Roberts 0:6b3ac9c5a042 2311 key = JSEncKey;
Wayne Roberts 0:6b3ac9c5a042 2312 DEBUG_CRYPT_BUF(JSEncKey, 16, "JSEncKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2313 }
Wayne Roberts 0:6b3ac9c5a042 2314 LoRaMacJoinDecrypt( rx_payload + 1, rx_size - 1, key, &_jaDecrypted[1]);
Wayne Roberts 0:6b3ac9c5a042 2315 DEBUG_CRYPT_BUF(_jaDecrypted, rx_size, "macbuf", 0);
Wayne Roberts 0:6b3ac9c5a042 2316
Wayne Roberts 0:6b3ac9c5a042 2317 _jaDecrypted[0] = macHdr.Value;
Wayne Roberts 0:6b3ac9c5a042 2318 ja = (joinAccept_t*)_jaDecrypted;
Wayne Roberts 0:6b3ac9c5a042 2319 flags.OptNeg = ja->fields.DLSettings.OptNeg;
Wayne Roberts 0:6b3ac9c5a042 2320
Wayne Roberts 0:6b3ac9c5a042 2321 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2322 uint8_t micBuf[40];
Wayne Roberts 0:6b3ac9c5a042 2323 uint8_t* ptr = micBuf;
Wayne Roberts 0:6b3ac9c5a042 2324 if (RootAppKey == NULL) {
Wayne Roberts 0:6b3ac9c5a042 2325 MAC_PRINTF("OptNeg-without-AppKey ");
Wayne Roberts 0:6b3ac9c5a042 2326 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_NO_APPKEY);
Wayne Roberts 0:6b3ac9c5a042 2327 return;
Wayne Roberts 0:6b3ac9c5a042 2328 }
Wayne Roberts 0:6b3ac9c5a042 2329 *ptr++ = JoinReqType;
Wayne Roberts 0:6b3ac9c5a042 2330 memcpyr(ptr, LoRaMacJoinEui, 8);
Wayne Roberts 0:6b3ac9c5a042 2331 ptr += 8;
Wayne Roberts 0:6b3ac9c5a042 2332 *ptr++ = LoRaMacDevNonce & 0xff;
Wayne Roberts 0:6b3ac9c5a042 2333 *ptr++ = LoRaMacDevNonce >> 8;
Wayne Roberts 0:6b3ac9c5a042 2334 memcpy(ptr, _jaDecrypted, rx_size - LORAMAC_MFR_LEN);
Wayne Roberts 0:6b3ac9c5a042 2335 ptr += rx_size - LORAMAC_MFR_LEN;
Wayne Roberts 0:6b3ac9c5a042 2336 DEBUG_MIC_BUF_DOWN(JSIntKey, 16, "JSIntKey", ROW_MIC);
Wayne Roberts 0:6b3ac9c5a042 2337 DEBUG_MIC_BUF_DOWN(micBuf, ptr - micBuf, "jaMic-in", ROW_MIC+1);
Wayne Roberts 0:6b3ac9c5a042 2338 if (LoRaMacJoinComputeMic(false, micBuf, ptr - micBuf, JSIntKey, &mic ) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2339 MAC_PRINTF("cryptFail\r\n");
Wayne Roberts 0:6b3ac9c5a042 2340 return;
Wayne Roberts 0:6b3ac9c5a042 2341 }
Wayne Roberts 0:6b3ac9c5a042 2342 } else {
Wayne Roberts 0:6b3ac9c5a042 2343 if (LoRaMacJoinComputeMic(false, _jaDecrypted, rx_size - LORAMAC_MFR_LEN, RootNwkKey, &mic ) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2344 MAC_PRINTF("cryptFail\r\n");
Wayne Roberts 0:6b3ac9c5a042 2345 return;
Wayne Roberts 0:6b3ac9c5a042 2346 }
Wayne Roberts 0:6b3ac9c5a042 2347 }
Wayne Roberts 0:6b3ac9c5a042 2348
Wayne Roberts 0:6b3ac9c5a042 2349 micRx = ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN];
Wayne Roberts 0:6b3ac9c5a042 2350 micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 1] << 8 );
Wayne Roberts 0:6b3ac9c5a042 2351 micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 2] << 16 );
Wayne Roberts 0:6b3ac9c5a042 2352 micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 3] << 24 );
Wayne Roberts 0:6b3ac9c5a042 2353
Wayne Roberts 0:6b3ac9c5a042 2354 MAC_PRINTF("JOIN_ACCEPT %u,OptNeg%" PRIu32" ", rx_size, flags.OptNeg);
Wayne Roberts 0:6b3ac9c5a042 2355
Wayne Roberts 0:6b3ac9c5a042 2356 if (micRx == mic)
Wayne Roberts 0:6b3ac9c5a042 2357 {
Wayne Roberts 7:4b6f960dcca2 2358 if (McpsIndication.RxSlot == 1) { // no need for RX2 with good mic on rx1
Wayne Roberts 0:6b3ac9c5a042 2359 RxWindowEvent2.detach();
Wayne Roberts 7:4b6f960dcca2 2360 }
Wayne Roberts 0:6b3ac9c5a042 2361
Wayne Roberts 0:6b3ac9c5a042 2362 #ifdef LORAWAN_ROOT_APPKEY
Wayne Roberts 0:6b3ac9c5a042 2363 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2364 MlmeConfirm.fields.join.myJoinNonce = eeprom_read(EEPROM_JOINNONCE);
Wayne Roberts 0:6b3ac9c5a042 2365 MlmeConfirm.fields.join.rxJoinNonce = ja->fields.joinNonce;
Wayne Roberts 0:6b3ac9c5a042 2366 if (MlmeConfirm.fields.join.rxJoinNonce <= MlmeConfirm.fields.join.myJoinNonce) {
Wayne Roberts 0:6b3ac9c5a042 2367 /* replay attack */
Wayne Roberts 0:6b3ac9c5a042 2368 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_JOINNONCE);
Wayne Roberts 0:6b3ac9c5a042 2369 return;
Wayne Roberts 0:6b3ac9c5a042 2370 }
Wayne Roberts 0:6b3ac9c5a042 2371 flags.need_ReKeyConf = 1;
Wayne Roberts 0:6b3ac9c5a042 2372 LoRaMacJoinComputeSKeys_1v1( RootNwkKey, RootAppKey, _jaDecrypted+1, LoRaMacJoinEui, LoRaMacDevNonce, &keys);
Wayne Roberts 0:6b3ac9c5a042 2373 eeprom_write_word(EEPROM_JOINNONCE, MlmeConfirm.fields.join.rxJoinNonce);
Wayne Roberts 0:6b3ac9c5a042 2374 } else
Wayne Roberts 0:6b3ac9c5a042 2375 #endif /* LORAWAN_ROOT_APPKEY */
Wayne Roberts 0:6b3ac9c5a042 2376 LoRaMacJoinComputeSKeys_1v0( RootNwkKey, _jaDecrypted+1, LoRaMacDevNonce, &keys);
Wayne Roberts 0:6b3ac9c5a042 2377
Wayne Roberts 0:6b3ac9c5a042 2378 DEBUG_CRYPT_BUF(keys.AppSKey , 16, "create-AppSKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2379
Wayne Roberts 0:6b3ac9c5a042 2380 LoRaMacNetID = ja->fields.Home_NetID;
Wayne Roberts 0:6b3ac9c5a042 2381 LoRaMacDevAddr = ja->fields.DevAddr;
Wayne Roberts 0:6b3ac9c5a042 2382
Wayne Roberts 0:6b3ac9c5a042 2383 // DLSettings
Wayne Roberts 0:6b3ac9c5a042 2384 LoRaMacParams.Rx1DrOffset = ja->fields.DLSettings.RX1DRoffset;
Wayne Roberts 0:6b3ac9c5a042 2385 LoRaMacParams.Rx2Channel.Datarate = ja->fields.DLSettings.RX2dr;
Wayne Roberts 0:6b3ac9c5a042 2386
Wayne Roberts 0:6b3ac9c5a042 2387 // RxDelay
Wayne Roberts 0:6b3ac9c5a042 2388 LoRaMacParams.ReceiveDelay1_us = (ja->fields.RxDelay & 0x0f) * 1000000;
Wayne Roberts 0:6b3ac9c5a042 2389 if( LoRaMacParams.ReceiveDelay1_us == 0 )
Wayne Roberts 0:6b3ac9c5a042 2390 {
Wayne Roberts 0:6b3ac9c5a042 2391 LoRaMacParams.ReceiveDelay1_us = 1000000;
Wayne Roberts 0:6b3ac9c5a042 2392 }
Wayne Roberts 0:6b3ac9c5a042 2393 LoRaMacParams.ReceiveDelay2_us = LoRaMacParams.ReceiveDelay1_us + 1000000;
Wayne Roberts 0:6b3ac9c5a042 2394 MAC_PRINTF("rx1droffset:%u, rx2dr%u rxDelays:%" PRIu32" %" PRIu32", devaddr:%08" PRIx32" ",
Wayne Roberts 0:6b3ac9c5a042 2395 LoRaMacParams.Rx1DrOffset,
Wayne Roberts 0:6b3ac9c5a042 2396 LoRaMacParams.Rx2Channel.Datarate,
Wayne Roberts 0:6b3ac9c5a042 2397 LoRaMacParams.ReceiveDelay1_us,
Wayne Roberts 0:6b3ac9c5a042 2398 LoRaMacParams.ReceiveDelay2_us,
Wayne Roberts 0:6b3ac9c5a042 2399 LoRaMacDevAddr
Wayne Roberts 0:6b3ac9c5a042 2400 );
Wayne Roberts 0:6b3ac9c5a042 2401
Wayne Roberts 0:6b3ac9c5a042 2402 #if !( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) // TODO
Wayne Roberts 0:6b3ac9c5a042 2403 //CFList
Wayne Roberts 0:6b3ac9c5a042 2404 if( ( rx_size - 1 ) > 16 )
Wayne Roberts 0:6b3ac9c5a042 2405 {
Wayne Roberts 0:6b3ac9c5a042 2406 ChannelParams_t param;
Wayne Roberts 0:6b3ac9c5a042 2407 param.DrRange.Value = ( LORAMAC_TX_MAX_DATARATE << 4 ) | LORAMAC_TX_MIN_DATARATE;
Wayne Roberts 0:6b3ac9c5a042 2408
Wayne Roberts 0:6b3ac9c5a042 2409 for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 )
Wayne Roberts 0:6b3ac9c5a042 2410 {
Wayne Roberts 0:6b3ac9c5a042 2411 param.FreqHz = ( ( uint32_t )_jaDecrypted[13 + j] | ( ( uint32_t )_jaDecrypted[14 + j] << 8 ) | ( ( uint32_t )_jaDecrypted[15 + j] << 16 ) ) * 100;
Wayne Roberts 0:6b3ac9c5a042 2412 if( param.FreqHz != 0 )
Wayne Roberts 0:6b3ac9c5a042 2413 {
Wayne Roberts 0:6b3ac9c5a042 2414 LoRaMacChannelAdd( i, param );
Wayne Roberts 0:6b3ac9c5a042 2415 }
Wayne Roberts 0:6b3ac9c5a042 2416 else
Wayne Roberts 0:6b3ac9c5a042 2417 {
Wayne Roberts 0:6b3ac9c5a042 2418 LoRaMacChannelRemove( i );
Wayne Roberts 0:6b3ac9c5a042 2419 }
Wayne Roberts 0:6b3ac9c5a042 2420 }
Wayne Roberts 0:6b3ac9c5a042 2421 }
Wayne Roberts 0:6b3ac9c5a042 2422 #endif
Wayne Roberts 0:6b3ac9c5a042 2423 status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2424 flags.IsLoRaMacNetworkJoined = true;
Wayne Roberts 0:6b3ac9c5a042 2425 LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 2426
Wayne Roberts 0:6b3ac9c5a042 2427 MAC_PRINTF("JoinReqType%x\r\n", JoinReqType);
Wayne Roberts 0:6b3ac9c5a042 2428 FCntUp = 0;
Wayne Roberts 0:6b3ac9c5a042 2429 NFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 2430 AFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 2431 ConfFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 2432 RJcount0 = 0;
Wayne Roberts 3:eb174e10afbb 2433 McpsIndication.ADR_ACK_CNT = 0;
Wayne Roberts 0:6b3ac9c5a042 2434
Wayne Roberts 0:6b3ac9c5a042 2435 rejoin.event.detach();
Wayne Roberts 0:6b3ac9c5a042 2436
Wayne Roberts 0:6b3ac9c5a042 2437 // must always notify application layer
Wayne Roberts 0:6b3ac9c5a042 2438 MlmeConfirm.MlmeRequest = MLME_JOIN;
Wayne Roberts 0:6b3ac9c5a042 2439 region_session_start(LORAMAC_EVENT_INFO_STATUS_OK);
Wayne Roberts 0:6b3ac9c5a042 2440 }
Wayne Roberts 0:6b3ac9c5a042 2441 else
Wayne Roberts 0:6b3ac9c5a042 2442 { /* join-accept mic fail */
Wayne Roberts 0:6b3ac9c5a042 2443 status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
dudmuck 2:c9c736b3e4eb 2444 MAC_PRINTF("ja-mic-fail rx:%" PRIx32 " calc:%" PRIx32" size:%d\r\n", micRx, mic, rx_size);
Wayne Roberts 0:6b3ac9c5a042 2445 if (MlmeIndication.MlmeIndication != MLME_NONE) {
dudmuck 2:c9c736b3e4eb 2446 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
Wayne Roberts 0:6b3ac9c5a042 2447 if (LoRaMacPrimitives->MacMlmeIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 2448 LoRaMacPrimitives->MacMlmeIndication(&MlmeIndication);
Wayne Roberts 0:6b3ac9c5a042 2449 }
Wayne Roberts 0:6b3ac9c5a042 2450 }
Wayne Roberts 0:6b3ac9c5a042 2451 break;
Wayne Roberts 0:6b3ac9c5a042 2452 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2453 case FRAME_TYPE_DATA_CONFIRMED_DOWN:
Wayne Roberts 0:6b3ac9c5a042 2454 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
Wayne Roberts 0:6b3ac9c5a042 2455 if (rx_downlink(pktHeaderLen, rx_payload, rx_size, snr, us_rxDone_at) == 0)
Wayne Roberts 0:6b3ac9c5a042 2456 status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2457 break;
Wayne Roberts 0:6b3ac9c5a042 2458 case FRAME_TYPE_PROPRIETARY:
Wayne Roberts 0:6b3ac9c5a042 2459 {
Wayne Roberts 0:6b3ac9c5a042 2460 McpsIndication.McpsIndication = MCPS_PROPRIETARY;
Wayne Roberts 0:6b3ac9c5a042 2461 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2462 McpsIndication.Buffer = Radio::radio.rx_buf;
Wayne Roberts 0:6b3ac9c5a042 2463 McpsIndication.BufferSize = rx_size - pktHeaderLen;
Wayne Roberts 0:6b3ac9c5a042 2464
Wayne Roberts 0:6b3ac9c5a042 2465 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 2466 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); // RxDone
Wayne Roberts 0:6b3ac9c5a042 2467 break;
Wayne Roberts 0:6b3ac9c5a042 2468 }
Wayne Roberts 0:6b3ac9c5a042 2469 default:
Wayne Roberts 0:6b3ac9c5a042 2470 MAC_PRINTF("unknown frame type:%02x\r\n", macHdr.Value);
Wayne Roberts 0:6b3ac9c5a042 2471 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_UNKNOWN_MTYPE);
Wayne Roberts 0:6b3ac9c5a042 2472 break;
Wayne Roberts 0:6b3ac9c5a042 2473 } // ..switch( macHdr.Bits.MType )
Wayne Roberts 0:6b3ac9c5a042 2474
Wayne Roberts 0:6b3ac9c5a042 2475 if (LoRaMacDeviceClass == CLASS_C) {
Wayne Roberts 0:6b3ac9c5a042 2476 if (McpsIndication.RxSlot == 1) {
Wayne Roberts 0:6b3ac9c5a042 2477 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 2478 RxWindow2Start(); // immiediately to continuous rx2 reception
Wayne Roberts 7:4b6f960dcca2 2479 } else if (McpsIndication.RxSlot == 2) {
Wayne Roberts 7:4b6f960dcca2 2480 /* stop simulated rx timeout for classC rx2-continuous */
Wayne Roberts 7:4b6f960dcca2 2481 RxWindowEvent2.detach();
Wayne Roberts 0:6b3ac9c5a042 2482 }
Wayne Roberts 0:6b3ac9c5a042 2483 }
Wayne Roberts 0:6b3ac9c5a042 2484
Wayne Roberts 0:6b3ac9c5a042 2485 {
Wayne Roberts 7:4b6f960dcca2 2486 if (flags.uplink_in_progress > 0)
Wayne Roberts 7:4b6f960dcca2 2487 finish_uplink(status);
Wayne Roberts 0:6b3ac9c5a042 2488
Wayne Roberts 0:6b3ac9c5a042 2489 mcps_confirm(status); // RxDone
Wayne Roberts 0:6b3ac9c5a042 2490 mlme_confirm(status);
Wayne Roberts 0:6b3ac9c5a042 2491 }
Wayne Roberts 0:6b3ac9c5a042 2492
Wayne Roberts 0:6b3ac9c5a042 2493 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 2494
Wayne Roberts 0:6b3ac9c5a042 2495 flags.rxing = false;
Wayne Roberts 0:6b3ac9c5a042 2496 } // ..OnRadioRxDone()
Wayne Roberts 0:6b3ac9c5a042 2497
Wayne Roberts 0:6b3ac9c5a042 2498 __attribute__((weak)) bool
Wayne Roberts 0:6b3ac9c5a042 2499 beacon_rx_timeout()
Wayne Roberts 0:6b3ac9c5a042 2500 {
Wayne Roberts 0:6b3ac9c5a042 2501 return false;
Wayne Roberts 0:6b3ac9c5a042 2502 }
Wayne Roberts 0:6b3ac9c5a042 2503
Wayne Roberts 0:6b3ac9c5a042 2504 void OnRadioRxTimeout( void )
Wayne Roberts 0:6b3ac9c5a042 2505 {
Wayne Roberts 0:6b3ac9c5a042 2506 MAC_PRINTF("OnRadioRxTimeout()%d ", McpsIndication.RxSlot);
Wayne Roberts 0:6b3ac9c5a042 2507 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2508 MAC_PRINTF(",%u ", flags.IsLoRaMacNetworkJoined);
Wayne Roberts 0:6b3ac9c5a042 2509 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2510
Wayne Roberts 0:6b3ac9c5a042 2511 if (beacon_rx_timeout())
Wayne Roberts 0:6b3ac9c5a042 2512 return;
Wayne Roberts 0:6b3ac9c5a042 2513
Wayne Roberts 0:6b3ac9c5a042 2514 if (McpsIndication.RxSlot == 1)
Wayne Roberts 0:6b3ac9c5a042 2515 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 2516
Wayne Roberts 7:4b6f960dcca2 2517 if (LoRaMacDeviceClass != CLASS_C)
Wayne Roberts 7:4b6f960dcca2 2518 Radio::Sleep();
Wayne Roberts 0:6b3ac9c5a042 2519
Wayne Roberts 0:6b3ac9c5a042 2520 if (McpsIndication.RxSlot == 2)
Wayne Roberts 0:6b3ac9c5a042 2521 {
Wayne Roberts 0:6b3ac9c5a042 2522 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2523 if (flags.IsLoRaMacNetworkJoined) {
Wayne Roberts 0:6b3ac9c5a042 2524 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2525 if (uplinkMHDR->Bits.MType == FRAME_TYPE_DATA_UNCONFIRMED_UP) {
Wayne Roberts 0:6b3ac9c5a042 2526 /* sent once, stoping now */
Wayne Roberts 0:6b3ac9c5a042 2527 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 2528 }
Wayne Roberts 0:6b3ac9c5a042 2529
Wayne Roberts 0:6b3ac9c5a042 2530 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 2531 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2532 } else {
Wayne Roberts 0:6b3ac9c5a042 2533 if (++MlmeIndication.JoinRequestTrials < MaxJoinRequestTrials) {
Wayne Roberts 4:e4bfe9183f94 2534 TxDelayedEvent.attach_us(OnTxDelayedIsr, 1000000);
Wayne Roberts 0:6b3ac9c5a042 2535 MAC_PRINTF("RxTImeout-join-tx-delay\r\n");
Wayne Roberts 0:6b3ac9c5a042 2536 MAC_PRINTF("join-try%u of%u ", MlmeIndication.JoinRequestTrials, MaxJoinRequestTrials);
Wayne Roberts 0:6b3ac9c5a042 2537
Wayne Roberts 0:6b3ac9c5a042 2538 if (MlmeIndication.MlmeIndication != MLME_NONE) {
Wayne Roberts 0:6b3ac9c5a042 2539 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
Wayne Roberts 0:6b3ac9c5a042 2540 if (LoRaMacPrimitives->MacMlmeIndication)
Wayne Roberts 0:6b3ac9c5a042 2541 LoRaMacPrimitives->MacMlmeIndication(&MlmeIndication);
Wayne Roberts 0:6b3ac9c5a042 2542 }
Wayne Roberts 0:6b3ac9c5a042 2543 } else {
Wayne Roberts 0:6b3ac9c5a042 2544 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL);
Wayne Roberts 0:6b3ac9c5a042 2545 }
Wayne Roberts 0:6b3ac9c5a042 2546 }
Wayne Roberts 0:6b3ac9c5a042 2547 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2548
Wayne Roberts 0:6b3ac9c5a042 2549 finish_uplink(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 2550 } // ..if (McpsIndication.RxSlot == 2)
Wayne Roberts 7:4b6f960dcca2 2551
Wayne Roberts 7:4b6f960dcca2 2552 if (LoRaMacDeviceClass == CLASS_C) {
Wayne Roberts 7:4b6f960dcca2 2553 if (McpsIndication.RxSlot != 2) {
Wayne Roberts 7:4b6f960dcca2 2554 RxWindow2Start();
Wayne Roberts 7:4b6f960dcca2 2555 }
Wayne Roberts 7:4b6f960dcca2 2556 } else
Wayne Roberts 7:4b6f960dcca2 2557 flags.rxing = false;
Wayne Roberts 7:4b6f960dcca2 2558
Wayne Roberts 0:6b3ac9c5a042 2559 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 2560
Wayne Roberts 0:6b3ac9c5a042 2561 } // ..OnRadioRxTimeout()
Wayne Roberts 0:6b3ac9c5a042 2562
Wayne Roberts 0:6b3ac9c5a042 2563 __attribute__((weak)) void
Wayne Roberts 0:6b3ac9c5a042 2564 on_dio0_top_half(us_timestamp_t dio0_at)
Wayne Roberts 0:6b3ac9c5a042 2565 {
Wayne Roberts 0:6b3ac9c5a042 2566 }
Wayne Roberts 0:6b3ac9c5a042 2567
Wayne Roberts 0:6b3ac9c5a042 2568 static void OnRadioRxError( void )
Wayne Roberts 0:6b3ac9c5a042 2569 {
Wayne Roberts 0:6b3ac9c5a042 2570 if( LoRaMacDeviceClass != CLASS_C )
Wayne Roberts 0:6b3ac9c5a042 2571 {
Wayne Roberts 8:5a5ea7cc946f 2572 Radio::Sleep();
Wayne Roberts 0:6b3ac9c5a042 2573 }
Wayne Roberts 0:6b3ac9c5a042 2574 else
Wayne Roberts 0:6b3ac9c5a042 2575 {
Wayne Roberts 0:6b3ac9c5a042 2576 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 2577 RxWindow2Start();
Wayne Roberts 0:6b3ac9c5a042 2578 }
Wayne Roberts 0:6b3ac9c5a042 2579
Wayne Roberts 0:6b3ac9c5a042 2580 if (McpsIndication.RxSlot == 2)
Wayne Roberts 0:6b3ac9c5a042 2581 {
Wayne Roberts 0:6b3ac9c5a042 2582 flags.uplink_in_progress = 0; // TODO check
Wayne Roberts 0:6b3ac9c5a042 2583 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_ERROR);
Wayne Roberts 0:6b3ac9c5a042 2584 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_ERROR);
Wayne Roberts 0:6b3ac9c5a042 2585 }
Wayne Roberts 0:6b3ac9c5a042 2586 } // ..OnRadioRxError
Wayne Roberts 0:6b3ac9c5a042 2587
Wayne Roberts 0:6b3ac9c5a042 2588 const RadioEvents_t RadioEvents = {
Wayne Roberts 0:6b3ac9c5a042 2589 /* Dio0_top_half */ on_dio0_top_half,
Wayne Roberts 0:6b3ac9c5a042 2590 /* TxDone */ OnRadioTxDone,
Wayne Roberts 0:6b3ac9c5a042 2591 /* TxTimeout */ OnRadioTxTimeout,
Wayne Roberts 0:6b3ac9c5a042 2592 /* RxDone */ OnRadioRxDone,
Wayne Roberts 0:6b3ac9c5a042 2593 /* RxTimeout */ OnRadioRxTimeout,
Wayne Roberts 0:6b3ac9c5a042 2594 /* RxError */ OnRadioRxError,
Wayne Roberts 0:6b3ac9c5a042 2595 /* FhssChangeChannel */ NULL,
Wayne Roberts 0:6b3ac9c5a042 2596 /* CadDone */ NULL
Wayne Roberts 0:6b3ac9c5a042 2597 };
Wayne Roberts 0:6b3ac9c5a042 2598
dudmuck 2:c9c736b3e4eb 2599
Wayne Roberts 0:6b3ac9c5a042 2600 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 2601 LoRaMacInitialization( const LoRaMacPrimitives_t *primitives, const LoRaMacCallback_t *callbacks )
Wayne Roberts 0:6b3ac9c5a042 2602 {
Wayne Roberts 0:6b3ac9c5a042 2603 if( primitives == NULL )
Wayne Roberts 0:6b3ac9c5a042 2604 {
Wayne Roberts 0:6b3ac9c5a042 2605 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 2606 }
Wayne Roberts 0:6b3ac9c5a042 2607
Wayne Roberts 0:6b3ac9c5a042 2608 if( ( primitives->MacMcpsConfirm == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 2609 ( primitives->MacMcpsIndication == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 2610 ( primitives->MacMlmeConfirm == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 2611 ( primitives->MacMlmeIndication == NULL ) )
Wayne Roberts 0:6b3ac9c5a042 2612 {
Wayne Roberts 0:6b3ac9c5a042 2613 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 2614 }
Wayne Roberts 0:6b3ac9c5a042 2615
dudmuck 2:c9c736b3e4eb 2616 if (targetCheckLSE() < 0)
dudmuck 2:c9c736b3e4eb 2617 return LORAMAC_STATUS_LSE;
Wayne Roberts 0:6b3ac9c5a042 2618
Wayne Roberts 0:6b3ac9c5a042 2619 LoRaMacPrimitives = primitives;
Wayne Roberts 0:6b3ac9c5a042 2620 LoRaMacCallbacks = callbacks;
Wayne Roberts 0:6b3ac9c5a042 2621
Wayne Roberts 0:6b3ac9c5a042 2622 LoRaMacDeviceClass = CLASS_A;
Wayne Roberts 0:6b3ac9c5a042 2623
Wayne Roberts 0:6b3ac9c5a042 2624 #ifdef DUTY_ENABLE
Wayne Roberts 0:6b3ac9c5a042 2625 DutyInit();
Wayne Roberts 0:6b3ac9c5a042 2626 #endif /* DUTY_ENABLE */
Wayne Roberts 0:6b3ac9c5a042 2627
Wayne Roberts 0:6b3ac9c5a042 2628 region_mac_init();
Wayne Roberts 0:6b3ac9c5a042 2629
Wayne Roberts 0:6b3ac9c5a042 2630 ResetMacParameters( );
Wayne Roberts 0:6b3ac9c5a042 2631
Wayne Roberts 0:6b3ac9c5a042 2632 // Initialize Radio driver
Wayne Roberts 0:6b3ac9c5a042 2633
Wayne Roberts 0:6b3ac9c5a042 2634 LoRaMacClassBInitialization();
Wayne Roberts 0:6b3ac9c5a042 2635 Radio::Init( &RadioEvents );
Wayne Roberts 0:6b3ac9c5a042 2636
Wayne Roberts 0:6b3ac9c5a042 2637 // Random seed initialization
Wayne Roberts 0:6b3ac9c5a042 2638 srand(Radio::Random());
Wayne Roberts 0:6b3ac9c5a042 2639
Wayne Roberts 0:6b3ac9c5a042 2640 flags.PublicNetwork = true;
Wayne Roberts 0:6b3ac9c5a042 2641 Radio::SetPublicNetwork( flags.PublicNetwork );
Wayne Roberts 8:5a5ea7cc946f 2642 Radio::Sleep();
Wayne Roberts 0:6b3ac9c5a042 2643
Wayne Roberts 0:6b3ac9c5a042 2644 McpsIndication.RxSlot = -1;
Wayne Roberts 0:6b3ac9c5a042 2645 function_pending = NULL;
Wayne Roberts 0:6b3ac9c5a042 2646
Wayne Roberts 0:6b3ac9c5a042 2647 McpsConfirm.McpsRequest = MCPS_NONE;
Wayne Roberts 0:6b3ac9c5a042 2648
Wayne Roberts 0:6b3ac9c5a042 2649 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2650 MaxJoinRequestTrials = 1;
Wayne Roberts 0:6b3ac9c5a042 2651 #else
Wayne Roberts 0:6b3ac9c5a042 2652 flags.have_SNwkSIntKey = 0;
Wayne Roberts 0:6b3ac9c5a042 2653 flags.have_NwkSEncKey = 0;
Wayne Roberts 0:6b3ac9c5a042 2654 flags.OptNeg = 0;
Wayne Roberts 0:6b3ac9c5a042 2655 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2656
Wayne Roberts 0:6b3ac9c5a042 2657 LoRaMacCryptoInit();
Wayne Roberts 0:6b3ac9c5a042 2658
Wayne Roberts 0:6b3ac9c5a042 2659 MlmeIndication.MlmeIndication = MLME_NONE;
Wayne Roberts 0:6b3ac9c5a042 2660
Wayne Roberts 3:eb174e10afbb 2661 ADR_ACK_LIMIT = DEFAULT_ADR_ACK_LIMIT;
Wayne Roberts 3:eb174e10afbb 2662 ADR_ACK_DELAY = DEFAULT_ADR_ACK_DELAY;
Wayne Roberts 3:eb174e10afbb 2663
Wayne Roberts 0:6b3ac9c5a042 2664 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2665 } // ..LoRaMacInitialization()
Wayne Roberts 0:6b3ac9c5a042 2666
Wayne Roberts 0:6b3ac9c5a042 2667 void SendFrameOnChannel( uint8_t ch_num )
Wayne Roberts 0:6b3ac9c5a042 2668 {
Wayne Roberts 0:6b3ac9c5a042 2669 int8_t txPowerIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 2670 int8_t txPower = 0;
Wayne Roberts 0:6b3ac9c5a042 2671 uint8_t tx_len = tx_buf_len;
Wayne Roberts 0:6b3ac9c5a042 2672 uint32_t mic;
Wayne Roberts 0:6b3ac9c5a042 2673
Wayne Roberts 0:6b3ac9c5a042 2674 /* TODO: if beacon guard, defer until pingslot 0 */
Wayne Roberts 0:6b3ac9c5a042 2675
Wayne Roberts 0:6b3ac9c5a042 2676 last_up_macHdr.Value = Radio::radio.tx_buf[0];
Wayne Roberts 0:6b3ac9c5a042 2677 if (last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_UNCONFIRMED_UP ||
Wayne Roberts 0:6b3ac9c5a042 2678 last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_UP)
Wayne Roberts 0:6b3ac9c5a042 2679 {
Wayne Roberts 3:eb174e10afbb 2680 LoRaMacFrameCtrl_t* fCtrl = (LoRaMacFrameCtrl_t*)&Radio::radio.tx_buf[5];
Wayne Roberts 0:6b3ac9c5a042 2681 block_t block;
Wayne Roberts 0:6b3ac9c5a042 2682 uint32_t fcnt_up;
Wayne Roberts 0:6b3ac9c5a042 2683 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2684 fcnt_up = FCntUp;
Wayne Roberts 0:6b3ac9c5a042 2685 #else
Wayne Roberts 0:6b3ac9c5a042 2686 fcnt_up = eeprom_read(EEPROM_FCNTUP);
Wayne Roberts 0:6b3ac9c5a042 2687 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 3:eb174e10afbb 2688
Wayne Roberts 3:eb174e10afbb 2689 fCtrl->Bits.AdrAckReq = false;
Wayne Roberts 3:eb174e10afbb 2690 if (fCtrl->Bits.Adr) {
Wayne Roberts 3:eb174e10afbb 2691 if (McpsIndication.ADR_ACK_CNT >= ADR_ACK_LIMIT) {
Wayne Roberts 3:eb174e10afbb 2692 if (LoRaMacParamsDefaults.ChannelsDatarate > LORAMAC_TX_MIN_DATARATE || LoRaMacParams.ChannelsTxPower > LORAMAC_DEFAULT_TX_POWER || LoRaMacParams.NbEnabledChannels < LoRaMacParamsDefaults.NbEnabledChannels)
Wayne Roberts 3:eb174e10afbb 2693 fCtrl->Bits.AdrAckReq = true;
Wayne Roberts 3:eb174e10afbb 2694
Wayne Roberts 3:eb174e10afbb 2695 if (McpsIndication.ADR_ACK_CNT >= (ADR_ACK_LIMIT + ADR_ACK_DELAY)) {
Wayne Roberts 3:eb174e10afbb 2696 /* if tx power less than default: increase tx power, otherwise decrease datarate */
Wayne Roberts 3:eb174e10afbb 2697 if (LoRaMacParams.ChannelsTxPower > LORAMAC_DEFAULT_TX_POWER) {
Wayne Roberts 3:eb174e10afbb 2698 LoRaMacParams.ChannelsTxPower--;
Wayne Roberts 3:eb174e10afbb 2699 } else if (LoRaMacParams.ChannelsDatarate > LORAMAC_TX_MIN_DATARATE) {
Wayne Roberts 3:eb174e10afbb 2700 LoRaMacParams.ChannelsDatarate--;
Wayne Roberts 3:eb174e10afbb 2701 McpsIndication.ADR_ACK_CNT -= ADR_ACK_DELAY;
Wayne Roberts 3:eb174e10afbb 2702 } else {
Wayne Roberts 3:eb174e10afbb 2703 memcpy(LoRaMacParams.ChannelsMask, LoRaMacParamsDefaults.ChannelsMask, sizeof(LoRaMacParams.ChannelsMask));
Wayne Roberts 3:eb174e10afbb 2704 LoRaMacParams.NbEnabledChannels = LoRaMacParamsDefaults.NbEnabledChannels;
Wayne Roberts 3:eb174e10afbb 2705 }
Wayne Roberts 3:eb174e10afbb 2706 }
Wayne Roberts 3:eb174e10afbb 2707 }
Wayne Roberts 3:eb174e10afbb 2708 } // ..if (fCtrl->Bits.Adr)
Wayne Roberts 3:eb174e10afbb 2709
Wayne Roberts 0:6b3ac9c5a042 2710 Radio::radio.tx_buf[6] = fcnt_up & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2711 Radio::radio.tx_buf[7] = ( fcnt_up >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2712
Wayne Roberts 0:6b3ac9c5a042 2713 block.b.header = 0x49;
Wayne Roberts 0:6b3ac9c5a042 2714 block.b.confFCnt = 0;
Wayne Roberts 0:6b3ac9c5a042 2715 block.b.dr = 0;
Wayne Roberts 0:6b3ac9c5a042 2716 block.b.ch = 0;
Wayne Roberts 0:6b3ac9c5a042 2717 block.b.dir = UP_LINK;
Wayne Roberts 0:6b3ac9c5a042 2718 block.b.DevAddr = LoRaMacDevAddr;
Wayne Roberts 0:6b3ac9c5a042 2719 block.b.FCnt = fcnt_up;
Wayne Roberts 0:6b3ac9c5a042 2720 block.b.zero8 = 0;
Wayne Roberts 0:6b3ac9c5a042 2721 block.b.lenMsg = tx_len;
Wayne Roberts 0:6b3ac9c5a042 2722 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2723 uint16_t cmacF, cmacS;
Wayne Roberts 0:6b3ac9c5a042 2724 cmacF = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.FNwkSIntKey);
Wayne Roberts 0:6b3ac9c5a042 2725
Wayne Roberts 0:6b3ac9c5a042 2726 block.b.confFCnt = ConfFCntDown;
Wayne Roberts 0:6b3ac9c5a042 2727 block.b.dr = LoRaMacParams.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 2728 block.b.ch = ch_num;
Wayne Roberts 0:6b3ac9c5a042 2729 cmacS = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.SNwkSIntKey) & 0xffff;
Wayne Roberts 0:6b3ac9c5a042 2730 mic = cmacS | (cmacF << 16);
Wayne Roberts 0:6b3ac9c5a042 2731 ConfFCntDown = 0; /* single use */
Wayne Roberts 0:6b3ac9c5a042 2732 } else
Wayne Roberts 0:6b3ac9c5a042 2733 mic = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.FNwkSIntKey);
Wayne Roberts 0:6b3ac9c5a042 2734
Wayne Roberts 0:6b3ac9c5a042 2735 Radio::radio.tx_buf[tx_buf_len + 0] = mic & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2736 Radio::radio.tx_buf[tx_buf_len + 1] = ( mic >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2737 Radio::radio.tx_buf[tx_buf_len + 2] = ( mic >> 16 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2738 Radio::radio.tx_buf[tx_buf_len + 3] = ( mic >> 24 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2739 tx_len += LORAMAC_MFR_LEN;
Wayne Roberts 0:6b3ac9c5a042 2740 MAC_PRINTF("FCntUp%u ", fcnt_up);
Wayne Roberts 0:6b3ac9c5a042 2741
Wayne Roberts 0:6b3ac9c5a042 2742 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2743 McpsConfirm.UpLinkCounter = FCntUp;
Wayne Roberts 0:6b3ac9c5a042 2744 #else
Wayne Roberts 0:6b3ac9c5a042 2745 McpsConfirm.UpLinkCounter = eeprom_read(EEPROM_FCNTUP);
Wayne Roberts 0:6b3ac9c5a042 2746 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 3:eb174e10afbb 2747
Wayne Roberts 3:eb174e10afbb 2748 if (flags.uplink_in_progress <= 1)
Wayne Roberts 3:eb174e10afbb 2749 McpsIndication.ADR_ACK_CNT++;
Wayne Roberts 3:eb174e10afbb 2750
Wayne Roberts 3:eb174e10afbb 2751 } // ..if sending (un)conf
Wayne Roberts 3:eb174e10afbb 2752
Wayne Roberts 3:eb174e10afbb 2753 txPowerIndex = region_LimitTxPower( LoRaMacParams.ChannelsTxPower );
Wayne Roberts 0:6b3ac9c5a042 2754 txPower = TxPowers[txPowerIndex];
Wayne Roberts 0:6b3ac9c5a042 2755
Wayne Roberts 0:6b3ac9c5a042 2756 if (MlmeConfirm.MlmeRequest != MLME_NONE) {
Wayne Roberts 0:6b3ac9c5a042 2757 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_SENDING;
Wayne Roberts 0:6b3ac9c5a042 2758 }
Wayne Roberts 0:6b3ac9c5a042 2759 if (McpsConfirm.McpsRequest != MCPS_NONE) {
Wayne Roberts 0:6b3ac9c5a042 2760 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_SENDING;
Wayne Roberts 0:6b3ac9c5a042 2761 McpsConfirm.Datarate = LoRaMacParams.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 2762 McpsConfirm.TxPower = txPowerIndex;
Wayne Roberts 0:6b3ac9c5a042 2763 McpsConfirm.UpLinkFreqHz = Channels[ch_num].FreqHz;
Wayne Roberts 0:6b3ac9c5a042 2764 }
Wayne Roberts 0:6b3ac9c5a042 2765
Wayne Roberts 0:6b3ac9c5a042 2766 Radio::SetChannel(Channels[ch_num].FreqHz);
Wayne Roberts 0:6b3ac9c5a042 2767 if (MlmeIndication.MlmeIndication != MLME_NONE)
Wayne Roberts 0:6b3ac9c5a042 2768 MlmeIndication.freqHz = Channels[ch_num].FreqHz;
Wayne Roberts 0:6b3ac9c5a042 2769
Wayne Roberts 0:6b3ac9c5a042 2770 region_tx_setup(txPower, tx_len);
Wayne Roberts 0:6b3ac9c5a042 2771
Wayne Roberts 0:6b3ac9c5a042 2772 // Store the time on air
Wayne Roberts 0:6b3ac9c5a042 2773 //McpsConfirm.TxTimeOnAir = TxTimeOnAir_us;
Wayne Roberts 0:6b3ac9c5a042 2774 //MlmeConfirm.TxTimeOnAir = TxTimeOnAir_us;
Wayne Roberts 0:6b3ac9c5a042 2775
Wayne Roberts 0:6b3ac9c5a042 2776 // Send now
Wayne Roberts 7:4b6f960dcca2 2777 if (Radio::Send(tx_len, LoRaMacParams.MaxListenTime, REGION_LBT_CHANNEL_FREE_TIME_us, REGION_LBT_RSSI_THRESHOLD_DBM) < 0) {
Wayne Roberts 7:4b6f960dcca2 2778 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_CHANNEL_BUSY); // SendFrame fail
Wayne Roberts 7:4b6f960dcca2 2779 return;
Wayne Roberts 7:4b6f960dcca2 2780 }
Wayne Roberts 5:4e9d41359897 2781 waitingFor = LORAMAC_STATUS_WAITING_FOR_TXDONE;
Wayne Roberts 0:6b3ac9c5a042 2782 MAC_PRINTF(" sfoc %u, %" PRIu32"hz\r\n", tx_len, Channels[ch_num].FreqHz);
Wayne Roberts 0:6b3ac9c5a042 2783
Wayne Roberts 3:eb174e10afbb 2784 /* if this is unconfirmed up, and last NbTrans */
Wayne Roberts 3:eb174e10afbb 2785 if (last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_UNCONFIRMED_UP && flags.uplink_in_progress <= 1) {
Wayne Roberts 0:6b3ac9c5a042 2786 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2787 FCntUp++;
Wayne Roberts 0:6b3ac9c5a042 2788 #else
Wayne Roberts 0:6b3ac9c5a042 2789 if (eeprom_increment_value(EEPROM_FCNTUP) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2790 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_INCR_FAIL); // SendFrame fail
Wayne Roberts 0:6b3ac9c5a042 2791 }
Wayne Roberts 0:6b3ac9c5a042 2792 #endif
Wayne Roberts 0:6b3ac9c5a042 2793 }
Wayne Roberts 0:6b3ac9c5a042 2794 } // ..SendFrameOnChannel()
Wayne Roberts 0:6b3ac9c5a042 2795
Wayne Roberts 0:6b3ac9c5a042 2796 uint8_t CountBits( uint16_t mask, uint8_t nbBits )
Wayne Roberts 0:6b3ac9c5a042 2797 {
Wayne Roberts 0:6b3ac9c5a042 2798 uint8_t nbActiveBits = 0;
Wayne Roberts 0:6b3ac9c5a042 2799
Wayne Roberts 0:6b3ac9c5a042 2800 for( uint8_t j = 0; j < nbBits; j++ )
Wayne Roberts 0:6b3ac9c5a042 2801 {
Wayne Roberts 0:6b3ac9c5a042 2802 if( ( mask & ( 1 << j ) ) == ( 1 << j ) )
Wayne Roberts 0:6b3ac9c5a042 2803 {
Wayne Roberts 0:6b3ac9c5a042 2804 nbActiveBits++;
Wayne Roberts 0:6b3ac9c5a042 2805 }
Wayne Roberts 0:6b3ac9c5a042 2806 }
Wayne Roberts 0:6b3ac9c5a042 2807 return nbActiveBits;
Wayne Roberts 0:6b3ac9c5a042 2808 }
Wayne Roberts 0:6b3ac9c5a042 2809
Wayne Roberts 0:6b3ac9c5a042 2810 void LoRaMacPrintStatus()
Wayne Roberts 0:6b3ac9c5a042 2811 {
Wayne Roberts 7:4b6f960dcca2 2812 #ifdef MAC_DEBUG
Wayne Roberts 7:4b6f960dcca2 2813 switch (waitingFor) {
Wayne Roberts 7:4b6f960dcca2 2814 case LORAMAC_STATUS_WAITING_FOR_TXSTART: MAC_PRINTF("wait-TXSTART "); break;
Wayne Roberts 7:4b6f960dcca2 2815 case LORAMAC_STATUS_WAITING_FOR_TXDONE: MAC_PRINTF("wait-TXDONE "); break;
Wayne Roberts 7:4b6f960dcca2 2816 case LORAMAC_STATUS_WAITING_FOR_RX1: MAC_PRINTF("wait-RX1 "); break;
Wayne Roberts 7:4b6f960dcca2 2817 case LORAMAC_STATUS_WAITING_FOR_RX2: MAC_PRINTF("wait-RX2 "); break;
Wayne Roberts 7:4b6f960dcca2 2818 default: break;
Wayne Roberts 7:4b6f960dcca2 2819 }
Wayne Roberts 7:4b6f960dcca2 2820 if (flags.uplink_in_progress > 0)
Wayne Roberts 7:4b6f960dcca2 2821 MAC_PRINTF("uplink_in_progress:%u ", flags.uplink_in_progress);
Wayne Roberts 7:4b6f960dcca2 2822 MAC_PRINTF("ConfFCntUp%u\r\n", ConfFCntUp);
Wayne Roberts 0:6b3ac9c5a042 2823 MAC_PRINTF("function_pending:%p\r\n", function_pending);
Wayne Roberts 0:6b3ac9c5a042 2824 MAC_PRINTF("rx delays:%u, %u, %u, %u\r\n",
Wayne Roberts 0:6b3ac9c5a042 2825 RxWindow1Delay_us,
Wayne Roberts 0:6b3ac9c5a042 2826 LoRaMacParams.ReceiveDelay1_us,
Wayne Roberts 0:6b3ac9c5a042 2827 RxWindow2Delay_us,
Wayne Roberts 0:6b3ac9c5a042 2828 LoRaMacParams.ReceiveDelay2_us
Wayne Roberts 0:6b3ac9c5a042 2829 );
Wayne Roberts 0:6b3ac9c5a042 2830 if (flags.uplink_in_progress) {
Wayne Roberts 0:6b3ac9c5a042 2831 MAC_PRINTF("since txDone:%u\r\n", Radio::lpt.read_us() - tx_done_at);
Wayne Roberts 0:6b3ac9c5a042 2832 }
Wayne Roberts 0:6b3ac9c5a042 2833
Wayne Roberts 7:4b6f960dcca2 2834 MAC_PRINTF("class-");
Wayne Roberts 7:4b6f960dcca2 2835 switch (LoRaMacDeviceClass) {
Wayne Roberts 7:4b6f960dcca2 2836 case CLASS_A: MAC_PRINTF("A "); break;
Wayne Roberts 7:4b6f960dcca2 2837 case CLASS_B: MAC_PRINTF("B "); break;
Wayne Roberts 7:4b6f960dcca2 2838 case CLASS_C: MAC_PRINTF("C "); break;
Wayne Roberts 7:4b6f960dcca2 2839 }
Wayne Roberts 7:4b6f960dcca2 2840 MAC_PRINTF("\r\n");
Wayne Roberts 7:4b6f960dcca2 2841
Wayne Roberts 0:6b3ac9c5a042 2842 Radio::PrintStatus();
Wayne Roberts 7:4b6f960dcca2 2843 #endif /* MAC_DEBUG */
Wayne Roberts 0:6b3ac9c5a042 2844 }
Wayne Roberts 0:6b3ac9c5a042 2845
Wayne Roberts 0:6b3ac9c5a042 2846 us_timestamp_t LoRaMacReadTimer()
Wayne Roberts 0:6b3ac9c5a042 2847 {
Wayne Roberts 0:6b3ac9c5a042 2848 return Radio::lpt.read_us();
Wayne Roberts 0:6b3ac9c5a042 2849 }
Wayne Roberts 0:6b3ac9c5a042 2850
Wayne Roberts 0:6b3ac9c5a042 2851 int8_t
Wayne Roberts 0:6b3ac9c5a042 2852 LoRaMacGetRxSlot()
Wayne Roberts 0:6b3ac9c5a042 2853 {
Wayne Roberts 0:6b3ac9c5a042 2854 return McpsIndication.RxSlot;
Wayne Roberts 0:6b3ac9c5a042 2855 }
Wayne Roberts 4:e4bfe9183f94 2856
Wayne Roberts 4:e4bfe9183f94 2857 void
Wayne Roberts 4:e4bfe9183f94 2858 LoRaMacUserContext()
Wayne Roberts 4:e4bfe9183f94 2859 {
Wayne Roberts 4:e4bfe9183f94 2860 Radio::UserContext();
Wayne Roberts 4:e4bfe9183f94 2861
Wayne Roberts 4:e4bfe9183f94 2862 if (flags.OnTxDelayed) {
Wayne Roberts 4:e4bfe9183f94 2863 OnTxDelayedTimerEvent();
Wayne Roberts 4:e4bfe9183f94 2864 flags.OnTxDelayed = false;
Wayne Roberts 4:e4bfe9183f94 2865 }
Wayne Roberts 4:e4bfe9183f94 2866 }
Wayne Roberts 4:e4bfe9183f94 2867