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

Dependencies:   sx12xx_hal

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

radio chip selection

Radio chip driver is not included, because two options are available.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.

application project requirements

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

{
    "macros": [ "MBEDTLS_CMAC_C" ]
}

regional PHY selection

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

end device provisioning

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

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

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

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


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


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

eeprom

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

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

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

radio driver support

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


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

low-speed clock oscillator selection

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

{
    "macros": [ "MBEDTLS_CMAC_C" ],
    "target_overrides": {
        "<your-target>": {
            "target.lse_available": true
        }
    }
}
Committer:
Wayne Roberts
Date:
Mon Mar 05 16:49:15 2018 -0800
Revision:
3:eb174e10afbb
Parent:
2:c9c736b3e4eb
Child:
4:e4bfe9183f94
correct ADR_ACK_CNT

Who changed what in which revision?

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