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:
dudmuck
Date:
Thu Mar 01 17:27:30 2018 +0000
Revision:
2:c9c736b3e4eb
Parent:
1:62f7347b9e17
Child:
3:eb174e10afbb
add LSE check

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