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:
Thu Mar 29 14:40:59 2018 -0700
Revision:
5:4e9d41359897
Parent:
4:e4bfe9183f94
Child:
7:4b6f960dcca2
report stalled timer failure codes

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