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 19 14:39:06 2018 -0700
Revision:
4:e4bfe9183f94
Parent:
3:eb174e10afbb
Child:
5:4e9d41359897
move mutex locks from ISR to user context

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 4:e4bfe9183f94 1169 void OnTxDelayedIsr()
Wayne Roberts 4:e4bfe9183f94 1170 {
Wayne Roberts 4:e4bfe9183f94 1171 flags.OnTxDelayed = true;
Wayne Roberts 4:e4bfe9183f94 1172 }
Wayne Roberts 4:e4bfe9183f94 1173
Wayne Roberts 4:e4bfe9183f94 1174 static void OnTxDelayedTimerEvent()
Wayne Roberts 0:6b3ac9c5a042 1175 {
Wayne Roberts 0:6b3ac9c5a042 1176 MAC_PRINTF("OnTxDelayedTimerEvent() ");
Wayne Roberts 0:6b3ac9c5a042 1177 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1178 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 1179 LoRaMacFrameCtrl_t fCtrl;
Wayne Roberts 0:6b3ac9c5a042 1180
Wayne Roberts 0:6b3ac9c5a042 1181 if (!flags.IsLoRaMacNetworkJoined)
Wayne Roberts 0:6b3ac9c5a042 1182 {
Wayne Roberts 0:6b3ac9c5a042 1183 // Add a +1, since we start to count from 0
Wayne Roberts 3:eb174e10afbb 1184 LoRaMacParams.ChannelsDatarate = region_AlternateDatarate( MlmeIndication.JoinRequestTrials + 1 );
Wayne Roberts 0:6b3ac9c5a042 1185
Wayne Roberts 0:6b3ac9c5a042 1186 macHdr.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 1187 macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
Wayne Roberts 0:6b3ac9c5a042 1188
Wayne Roberts 0:6b3ac9c5a042 1189 fCtrl.Value = 0;
Wayne Roberts 0:6b3ac9c5a042 1190 fCtrl.Bits.Adr = flags.AdrCtrlOn;
Wayne Roberts 0:6b3ac9c5a042 1191
Wayne Roberts 0:6b3ac9c5a042 1192 /* In case of join request retransmissions, the stack must prepare
Wayne Roberts 0:6b3ac9c5a042 1193 * the frame again, because the network server keeps track of the random
Wayne Roberts 0:6b3ac9c5a042 1194 * LoRaMacDevNonce values to prevent reply attacks. */
Wayne Roberts 0:6b3ac9c5a042 1195 PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 );
Wayne Roberts 0:6b3ac9c5a042 1196 /* TODO PrepareFrame() != LORAMAC_STATUS_OK */
Wayne Roberts 0:6b3ac9c5a042 1197 }
Wayne Roberts 0:6b3ac9c5a042 1198 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1199
Wayne Roberts 0:6b3ac9c5a042 1200 if (flags.rxing)
Wayne Roberts 0:6b3ac9c5a042 1201 function_pending = region_ScheduleTx;
Wayne Roberts 0:6b3ac9c5a042 1202 else {
Wayne Roberts 0:6b3ac9c5a042 1203 region_ScheduleTx( );
Wayne Roberts 0:6b3ac9c5a042 1204 }
Wayne Roberts 0:6b3ac9c5a042 1205 } // ..OnTxDelayedTimerEvent()
Wayne Roberts 0:6b3ac9c5a042 1206
Wayne Roberts 0:6b3ac9c5a042 1207 static void RxWindow2Setup(void)
Wayne Roberts 0:6b3ac9c5a042 1208 {
Wayne Roberts 0:6b3ac9c5a042 1209 MAC_PRINTF("RxWindow2Setup %uhz dr%u", LoRaMacParams.Rx2Channel.FrequencyHz, LoRaMacParams.Rx2Channel.Datarate);
Wayne Roberts 0:6b3ac9c5a042 1210 RxWindowSetup(
Wayne Roberts 0:6b3ac9c5a042 1211 LoRaMacParams.Rx2Channel.FrequencyHz,
Wayne Roberts 0:6b3ac9c5a042 1212 LoRaMacParams.Rx2Channel.Datarate,
Wayne Roberts 0:6b3ac9c5a042 1213 region_GetRxBandwidth( LoRaMacParams.Rx2Channel.Datarate ),
Wayne Roberts 0:6b3ac9c5a042 1214 region_GetRxSymbolTimeout( LoRaMacParams.Rx2Channel.Datarate )
Wayne Roberts 0:6b3ac9c5a042 1215 );
Wayne Roberts 0:6b3ac9c5a042 1216 }
Wayne Roberts 0:6b3ac9c5a042 1217
Wayne Roberts 0:6b3ac9c5a042 1218 static void
Wayne Roberts 0:6b3ac9c5a042 1219 PrepareRxDoneAbort(LoRaMacEventInfoStatus_t status)
Wayne Roberts 0:6b3ac9c5a042 1220 {
Wayne Roberts 0:6b3ac9c5a042 1221 MAC_PRINTF("rxAbort ");
Wayne Roberts 0:6b3ac9c5a042 1222 if( ( McpsIndication.RxSlot == 1 ) && ( LoRaMacDeviceClass == CLASS_C ) )
Wayne Roberts 0:6b3ac9c5a042 1223 {
Wayne Roberts 0:6b3ac9c5a042 1224 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 1225 RxWindow2Start(); // start continuous rx2 reception
Wayne Roberts 0:6b3ac9c5a042 1226 }
Wayne Roberts 0:6b3ac9c5a042 1227
Wayne Roberts 0:6b3ac9c5a042 1228 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1229 if (!flags.IsLoRaMacNetworkJoined && LoRaMacJoinEui != NULL && LoRaMacDevEui == NULL) {
Wayne Roberts 4:e4bfe9183f94 1230 TxDelayedEvent.attach_us(OnTxDelayedIsr, 1000000);
Wayne Roberts 0:6b3ac9c5a042 1231 MAC_PRINTF("RxDoneAbort-join-tx-delay");
Wayne Roberts 0:6b3ac9c5a042 1232 }
Wayne Roberts 0:6b3ac9c5a042 1233 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1234
Wayne Roberts 0:6b3ac9c5a042 1235
Wayne Roberts 0:6b3ac9c5a042 1236 McpsIndication.Status = status;
Wayne Roberts 0:6b3ac9c5a042 1237 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 1238 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); // RxAbort
Wayne Roberts 0:6b3ac9c5a042 1239
Wayne Roberts 0:6b3ac9c5a042 1240 mcps_confirm(status); // RXAbort
Wayne Roberts 0:6b3ac9c5a042 1241 mlme_confirm(status);
Wayne Roberts 0:6b3ac9c5a042 1242
Wayne Roberts 0:6b3ac9c5a042 1243 finish_uplink(status);
Wayne Roberts 0:6b3ac9c5a042 1244
Wayne Roberts 0:6b3ac9c5a042 1245 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 1246
Wayne Roberts 0:6b3ac9c5a042 1247 } // ..PrepareRxDoneAbort()
Wayne Roberts 0:6b3ac9c5a042 1248
Wayne Roberts 0:6b3ac9c5a042 1249
Wayne Roberts 0:6b3ac9c5a042 1250 static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
Wayne Roberts 0:6b3ac9c5a042 1251 {
Wayne Roberts 0:6b3ac9c5a042 1252 LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1253
Wayne Roberts 0:6b3ac9c5a042 1254 switch( LoRaMacDeviceClass )
Wayne Roberts 0:6b3ac9c5a042 1255 {
Wayne Roberts 0:6b3ac9c5a042 1256 case CLASS_A:
Wayne Roberts 0:6b3ac9c5a042 1257 {
Wayne Roberts 0:6b3ac9c5a042 1258 MAC_PRINTF("CLASS_A ");
Wayne Roberts 0:6b3ac9c5a042 1259 if (deviceClass == CLASS_B)
Wayne Roberts 0:6b3ac9c5a042 1260 status = SwitchClassB(deviceClass);
Wayne Roberts 0:6b3ac9c5a042 1261
Wayne Roberts 0:6b3ac9c5a042 1262 if (deviceClass == CLASS_C)
Wayne Roberts 0:6b3ac9c5a042 1263 {
Wayne Roberts 0:6b3ac9c5a042 1264 MAC_PRINTF("->C ");
Wayne Roberts 0:6b3ac9c5a042 1265 LoRaMacDeviceClass = deviceClass;
Wayne Roberts 0:6b3ac9c5a042 1266 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 1267 RxWindow2Start(); // continuous rx2 reception
Wayne Roberts 0:6b3ac9c5a042 1268
Wayne Roberts 0:6b3ac9c5a042 1269 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1270 }
Wayne Roberts 0:6b3ac9c5a042 1271 break;
Wayne Roberts 0:6b3ac9c5a042 1272 }
Wayne Roberts 0:6b3ac9c5a042 1273 case CLASS_B:
Wayne Roberts 0:6b3ac9c5a042 1274 {
Wayne Roberts 0:6b3ac9c5a042 1275 MAC_PRINTF("CLASS_B ");
Wayne Roberts 0:6b3ac9c5a042 1276 if( deviceClass == CLASS_A )
Wayne Roberts 0:6b3ac9c5a042 1277 {
Wayne Roberts 0:6b3ac9c5a042 1278 MAC_PRINTF("->A ");
Wayne Roberts 0:6b3ac9c5a042 1279 LoRaMacDeviceClass = deviceClass;
Wayne Roberts 0:6b3ac9c5a042 1280 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1281 }
Wayne Roberts 0:6b3ac9c5a042 1282 break;
Wayne Roberts 0:6b3ac9c5a042 1283 }
Wayne Roberts 0:6b3ac9c5a042 1284 case CLASS_C:
Wayne Roberts 0:6b3ac9c5a042 1285 {
Wayne Roberts 0:6b3ac9c5a042 1286 MAC_PRINTF("CLASS_C ");
Wayne Roberts 0:6b3ac9c5a042 1287 if( deviceClass == CLASS_A )
Wayne Roberts 0:6b3ac9c5a042 1288 {
Wayne Roberts 0:6b3ac9c5a042 1289 MAC_PRINTF("->A ");
Wayne Roberts 0:6b3ac9c5a042 1290 LoRaMacDeviceClass = deviceClass;
Wayne Roberts 0:6b3ac9c5a042 1291
Wayne Roberts 0:6b3ac9c5a042 1292 // Set the radio into sleep to setup a defined state
Wayne Roberts 0:6b3ac9c5a042 1293 Radio::Sleep( );
Wayne Roberts 0:6b3ac9c5a042 1294
Wayne Roberts 0:6b3ac9c5a042 1295 status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1296 }
Wayne Roberts 0:6b3ac9c5a042 1297 break;
Wayne Roberts 0:6b3ac9c5a042 1298 }
Wayne Roberts 0:6b3ac9c5a042 1299 }
Wayne Roberts 0:6b3ac9c5a042 1300
Wayne Roberts 0:6b3ac9c5a042 1301 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 1302 return status;
Wayne Roberts 0:6b3ac9c5a042 1303 }
Wayne Roberts 0:6b3ac9c5a042 1304
Wayne Roberts 0:6b3ac9c5a042 1305 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 1306 LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
Wayne Roberts 0:6b3ac9c5a042 1307 {
Wayne Roberts 0:6b3ac9c5a042 1308 LoRaMacStatus_t status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1309
Wayne Roberts 0:6b3ac9c5a042 1310 if (mibSet == NULL)
Wayne Roberts 0:6b3ac9c5a042 1311 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1312
Wayne Roberts 0:6b3ac9c5a042 1313 if (flags.uplink_in_progress > 0)
Wayne Roberts 0:6b3ac9c5a042 1314 return LORAMAC_STATUS_IN_PROGRESS;
Wayne Roberts 0:6b3ac9c5a042 1315
Wayne Roberts 0:6b3ac9c5a042 1316 switch (mibSet->Type) {
Wayne Roberts 0:6b3ac9c5a042 1317 case MIB_CHANNELS_MASK:
Wayne Roberts 0:6b3ac9c5a042 1318 if( mibSet->Param.ChannelsMask )
Wayne Roberts 0:6b3ac9c5a042 1319 {
Wayne Roberts 0:6b3ac9c5a042 1320 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1321 bool chanMaskState = true;
Wayne Roberts 0:6b3ac9c5a042 1322
Wayne Roberts 0:6b3ac9c5a042 1323 #if defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1324 chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsMask );
Wayne Roberts 0:6b3ac9c5a042 1325 #endif
Wayne Roberts 0:6b3ac9c5a042 1326 if( chanMaskState == true )
Wayne Roberts 0:6b3ac9c5a042 1327 {
Wayne Roberts 0:6b3ac9c5a042 1328 if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) &&
Wayne Roberts 0:6b3ac9c5a042 1329 ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
Wayne Roberts 0:6b3ac9c5a042 1330 {
Wayne Roberts 0:6b3ac9c5a042 1331 status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1332 }
Wayne Roberts 0:6b3ac9c5a042 1333 else
Wayne Roberts 0:6b3ac9c5a042 1334 {
Wayne Roberts 0:6b3ac9c5a042 1335 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask,
Wayne Roberts 0:6b3ac9c5a042 1336 ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
Wayne Roberts 0:6b3ac9c5a042 1337 for ( uint8_t i = 0; i < sizeof( LoRaMacParams.ChannelsMask ) / 2; i++ )
Wayne Roberts 0:6b3ac9c5a042 1338 {
Wayne Roberts 0:6b3ac9c5a042 1339 // Disable channels which are no longer available
Wayne Roberts 0:6b3ac9c5a042 1340 ChannelsMaskRemaining[i] &= LoRaMacParams.ChannelsMask[i];
Wayne Roberts 0:6b3ac9c5a042 1341 }
Wayne Roberts 0:6b3ac9c5a042 1342 }
Wayne Roberts 0:6b3ac9c5a042 1343 }
Wayne Roberts 0:6b3ac9c5a042 1344 else
Wayne Roberts 0:6b3ac9c5a042 1345 {
Wayne Roberts 0:6b3ac9c5a042 1346 status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1347 }
Wayne Roberts 0:6b3ac9c5a042 1348 #elif defined( USE_BAND_470 )
Wayne Roberts 0:6b3ac9c5a042 1349 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask,
Wayne Roberts 0:6b3ac9c5a042 1350 ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
Wayne Roberts 0:6b3ac9c5a042 1351 #else
Wayne Roberts 0:6b3ac9c5a042 1352 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask,
Wayne Roberts 0:6b3ac9c5a042 1353 ( uint8_t* ) mibSet->Param.ChannelsMask, 2 );
Wayne Roberts 0:6b3ac9c5a042 1354 #endif
Wayne Roberts 3:eb174e10afbb 1355 LoRaMacParams.NbEnabledChannels = region_CountNbEnabledChannels();
Wayne Roberts 0:6b3ac9c5a042 1356 }
Wayne Roberts 0:6b3ac9c5a042 1357 else
Wayne Roberts 0:6b3ac9c5a042 1358 {
Wayne Roberts 0:6b3ac9c5a042 1359 status = LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1360 }
Wayne Roberts 0:6b3ac9c5a042 1361 break;
Wayne Roberts 0:6b3ac9c5a042 1362 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1363 /* values which cannot be set in OTA */
Wayne Roberts 0:6b3ac9c5a042 1364 case MIB_NwkSKey:
Wayne Roberts 0:6b3ac9c5a042 1365 case MIB_SNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 1366 case MIB_NwkSEncKey:
Wayne Roberts 0:6b3ac9c5a042 1367 case MIB_FNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 1368 case MIB_APP_SKEY:
Wayne Roberts 0:6b3ac9c5a042 1369 case MIB_DEV_ADDR:
Wayne Roberts 0:6b3ac9c5a042 1370 case MIB_NETWORK_JOINED:
Wayne Roberts 0:6b3ac9c5a042 1371 #endif
Wayne Roberts 0:6b3ac9c5a042 1372 case MIB_RX2_CHANNEL:
Wayne Roberts 0:6b3ac9c5a042 1373 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 1374 case MIB_DEVICE_CLASS:
Wayne Roberts 0:6b3ac9c5a042 1375 status = SwitchClass(mibSet->Param.Class);
Wayne Roberts 0:6b3ac9c5a042 1376 break;
Wayne Roberts 0:6b3ac9c5a042 1377 case MIB_ADR:
Wayne Roberts 0:6b3ac9c5a042 1378 flags.AdrCtrlOn = mibSet->Param.AdrEnable;
Wayne Roberts 0:6b3ac9c5a042 1379 break;
Wayne Roberts 0:6b3ac9c5a042 1380 case MIB_PUBLIC_NETWORK:
Wayne Roberts 0:6b3ac9c5a042 1381 flags.PublicNetwork = mibSet->Param.EnablePublicNetwork;
Wayne Roberts 0:6b3ac9c5a042 1382 Radio::SetPublicNetwork( flags.PublicNetwork );
Wayne Roberts 0:6b3ac9c5a042 1383 break;
Wayne Roberts 0:6b3ac9c5a042 1384 #ifndef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1385 case MIB_SNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 1386 flags.have_SNwkSIntKey = 1;
Wayne Roberts 0:6b3ac9c5a042 1387 memcpy( keys.SNwkSIntKey, mibSet->Param.key, sizeof(keys.SNwkSIntKey) );
Wayne Roberts 0:6b3ac9c5a042 1388 if (flags.have_NwkSEncKey) {
Wayne Roberts 0:6b3ac9c5a042 1389 flags.OptNeg = 1;
Wayne Roberts 0:6b3ac9c5a042 1390 flags.need_ResetConf = 1;
Wayne Roberts 0:6b3ac9c5a042 1391 }
Wayne Roberts 0:6b3ac9c5a042 1392 break;
Wayne Roberts 0:6b3ac9c5a042 1393 case MIB_NwkSEncKey:
Wayne Roberts 0:6b3ac9c5a042 1394 flags.have_NwkSEncKey = 1;
Wayne Roberts 0:6b3ac9c5a042 1395 memcpy( keys.NwkSEncKey, mibSet->Param.key, sizeof(keys.NwkSEncKey) );
Wayne Roberts 0:6b3ac9c5a042 1396 if (flags.have_SNwkSIntKey) {
Wayne Roberts 0:6b3ac9c5a042 1397 flags.OptNeg = 1;
Wayne Roberts 0:6b3ac9c5a042 1398 flags.need_ResetConf = 1;
Wayne Roberts 0:6b3ac9c5a042 1399 }
Wayne Roberts 0:6b3ac9c5a042 1400 break;
Wayne Roberts 0:6b3ac9c5a042 1401 case MIB_APP_SKEY:
Wayne Roberts 0:6b3ac9c5a042 1402 memcpy( keys.AppSKey, mibSet->Param.key, sizeof( keys.AppSKey ) );
Wayne Roberts 0:6b3ac9c5a042 1403 break;
Wayne Roberts 0:6b3ac9c5a042 1404 case MIB_FNwkSIntKey:
Wayne Roberts 0:6b3ac9c5a042 1405 memcpy( keys.FNwkSIntKey, mibSet->Param.key, sizeof( keys.FNwkSIntKey ) );
Wayne Roberts 0:6b3ac9c5a042 1406 break;
Wayne Roberts 0:6b3ac9c5a042 1407 case MIB_NwkSKey:
Wayne Roberts 0:6b3ac9c5a042 1408 /* lorawan 1.0 ABP */
Wayne Roberts 0:6b3ac9c5a042 1409 memcpy( keys.FNwkSIntKey, mibSet->Param.key, sizeof( keys.FNwkSIntKey ) );
Wayne Roberts 0:6b3ac9c5a042 1410 memcpy( keys.SNwkSIntKey, mibSet->Param.key, sizeof( keys.SNwkSIntKey) );
Wayne Roberts 0:6b3ac9c5a042 1411 memcpy( keys.NwkSEncKey, mibSet->Param.key, sizeof( keys.NwkSEncKey) );
Wayne Roberts 0:6b3ac9c5a042 1412 flags.OptNeg = 0;
Wayne Roberts 0:6b3ac9c5a042 1413 break;
Wayne Roberts 0:6b3ac9c5a042 1414 case MIB_DEV_ADDR:
Wayne Roberts 0:6b3ac9c5a042 1415 LoRaMacDevAddr = mibSet->Param.DevAddr;
Wayne Roberts 0:6b3ac9c5a042 1416 break;
Wayne Roberts 0:6b3ac9c5a042 1417 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1418 } // ..switch( mibSet->Type )
Wayne Roberts 0:6b3ac9c5a042 1419
Wayne Roberts 0:6b3ac9c5a042 1420 return status;
Wayne Roberts 0:6b3ac9c5a042 1421 } // ..LoRaMacMibSetRequestConfirm()
Wayne Roberts 0:6b3ac9c5a042 1422
Wayne Roberts 0:6b3ac9c5a042 1423 __attribute__((weak)) LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 1424 LoRaMacClassBInitialization( void )
Wayne Roberts 0:6b3ac9c5a042 1425 {
Wayne Roberts 0:6b3ac9c5a042 1426 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1427 }
Wayne Roberts 0:6b3ac9c5a042 1428
Wayne Roberts 0:6b3ac9c5a042 1429 LowPowerTimeout RxWindowEvent1;
Wayne Roberts 0:6b3ac9c5a042 1430 LowPowerTimeout RxWindowEvent2;
Wayne Roberts 0:6b3ac9c5a042 1431
Wayne Roberts 0:6b3ac9c5a042 1432 static void RxWindow1Start( void )
dudmuck 2:c9c736b3e4eb 1433 {
Wayne Roberts 0:6b3ac9c5a042 1434 if (LoRaMacDeviceClass == CLASS_C)
Wayne Roberts 0:6b3ac9c5a042 1435 Radio::Rx( 0 ); // Continuous mode
Wayne Roberts 0:6b3ac9c5a042 1436 else
Wayne Roberts 0:6b3ac9c5a042 1437 Radio::Rx( LoRaMacParams.MaxRxWindow_us );
Wayne Roberts 0:6b3ac9c5a042 1438
Wayne Roberts 0:6b3ac9c5a042 1439 McpsIndication.RxSlot = 1;
Wayne Roberts 0:6b3ac9c5a042 1440 }
Wayne Roberts 0:6b3ac9c5a042 1441
Wayne Roberts 0:6b3ac9c5a042 1442 volatile us_timestamp_t tx_done_at;
Wayne Roberts 0:6b3ac9c5a042 1443
Wayne Roberts 0:6b3ac9c5a042 1444 static void OnRadioTxDone( us_timestamp_t at_us )
Wayne Roberts 0:6b3ac9c5a042 1445 {
Wayne Roberts 0:6b3ac9c5a042 1446 if ((RxWindow1Delay_us < 100000 || RxWindow1Delay_us > 10000000) ||
Wayne Roberts 0:6b3ac9c5a042 1447 (RxWindow2Delay_us < 100000 || RxWindow2Delay_us > 10000000))
Wayne Roberts 0:6b3ac9c5a042 1448 {
Wayne Roberts 0:6b3ac9c5a042 1449 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_BAD_RX_DELAY);
Wayne Roberts 0:6b3ac9c5a042 1450 return;
Wayne Roberts 0:6b3ac9c5a042 1451 }
Wayne Roberts 0:6b3ac9c5a042 1452 // Setup timers
Wayne Roberts 0:6b3ac9c5a042 1453 RxWindowEvent1.attach_us(RxWindow1Start, RxWindow1Delay_us);
Wayne Roberts 0:6b3ac9c5a042 1454 if( LoRaMacDeviceClass != CLASS_C )
Wayne Roberts 0:6b3ac9c5a042 1455 {
Wayne Roberts 0:6b3ac9c5a042 1456 RxWindowEvent2.attach_us(RxWindow2Start, RxWindow2Delay_us);
Wayne Roberts 0:6b3ac9c5a042 1457 }
Wayne Roberts 0:6b3ac9c5a042 1458 McpsIndication.RxSlot = 0;
Wayne Roberts 0:6b3ac9c5a042 1459
Wayne Roberts 0:6b3ac9c5a042 1460 tx_done_at = at_us;
Wayne Roberts 0:6b3ac9c5a042 1461
Wayne Roberts 0:6b3ac9c5a042 1462 if( LoRaMacDeviceClass != CLASS_C )
Wayne Roberts 0:6b3ac9c5a042 1463 {
Wayne Roberts 0:6b3ac9c5a042 1464 region_rx1_setup(Channel);
Wayne Roberts 0:6b3ac9c5a042 1465 Radio::Sleep( );
Wayne Roberts 0:6b3ac9c5a042 1466 }
Wayne Roberts 0:6b3ac9c5a042 1467 else
Wayne Roberts 0:6b3ac9c5a042 1468 {
Wayne Roberts 0:6b3ac9c5a042 1469 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 1470 RxWindow2Start();
Wayne Roberts 0:6b3ac9c5a042 1471 }
Wayne Roberts 0:6b3ac9c5a042 1472
Wayne Roberts 0:6b3ac9c5a042 1473 // Store last tx channel
Wayne Roberts 0:6b3ac9c5a042 1474 //LastTxChannel = Channel;
Wayne Roberts 0:6b3ac9c5a042 1475 #ifdef DUTY_ENABLE
Wayne Roberts 0:6b3ac9c5a042 1476 DutyTxDone(at_us);
Wayne Roberts 0:6b3ac9c5a042 1477 #endif /* DUTY_ENABLE */
Wayne Roberts 0:6b3ac9c5a042 1478
Wayne Roberts 0:6b3ac9c5a042 1479 } // ..OnRadioTxDone()
Wayne Roberts 0:6b3ac9c5a042 1480
Wayne Roberts 0:6b3ac9c5a042 1481 static void OnRadioTxTimeout( void )
Wayne Roberts 0:6b3ac9c5a042 1482 {
Wayne Roberts 0:6b3ac9c5a042 1483 if( LoRaMacDeviceClass != CLASS_C )
Wayne Roberts 0:6b3ac9c5a042 1484 {
Wayne Roberts 0:6b3ac9c5a042 1485 Radio::Sleep( );
Wayne Roberts 0:6b3ac9c5a042 1486 }
Wayne Roberts 0:6b3ac9c5a042 1487 else
Wayne Roberts 0:6b3ac9c5a042 1488 {
Wayne Roberts 0:6b3ac9c5a042 1489 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 1490 RxWindow2Start();
Wayne Roberts 0:6b3ac9c5a042 1491 }
Wayne Roberts 0:6b3ac9c5a042 1492
Wayne Roberts 0:6b3ac9c5a042 1493 finish_uplink(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 1494
Wayne Roberts 0:6b3ac9c5a042 1495 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 1496 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 1497 } // ..OnRadioTxTimeout()
Wayne Roberts 0:6b3ac9c5a042 1498
Wayne Roberts 0:6b3ac9c5a042 1499 __attribute__((weak)) bool
Wayne Roberts 0:6b3ac9c5a042 1500 beacon_rx_done_payload(uint8_t* payload, uint16_t size)
Wayne Roberts 0:6b3ac9c5a042 1501 {
Wayne Roberts 0:6b3ac9c5a042 1502 return false;
Wayne Roberts 0:6b3ac9c5a042 1503 }
Wayne Roberts 0:6b3ac9c5a042 1504
Wayne Roberts 0:6b3ac9c5a042 1505 static void
Wayne Roberts 0:6b3ac9c5a042 1506 print_mtype(uint8_t mt)
Wayne Roberts 0:6b3ac9c5a042 1507 {
Wayne Roberts 0:6b3ac9c5a042 1508 #ifdef MAC_DEBUG
Wayne Roberts 0:6b3ac9c5a042 1509 const char* cp;
Wayne Roberts 0:6b3ac9c5a042 1510 switch (mt) {
Wayne Roberts 0:6b3ac9c5a042 1511 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1512 case FRAME_TYPE_JOIN_REQ: cp = "JOIN_REQ "; break;
Wayne Roberts 0:6b3ac9c5a042 1513 case FRAME_TYPE_JOIN_ACCEPT: cp = "JOIN_ACC "; break;
Wayne Roberts 0:6b3ac9c5a042 1514 case FRAME_TYPE_REJOIN_REQ: cp = "REJOIN_REQ"; break;
Wayne Roberts 0:6b3ac9c5a042 1515 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1516 case FRAME_TYPE_DATA_UNCONFIRMED_UP: cp = "UNCONF_UP"; break;
Wayne Roberts 0:6b3ac9c5a042 1517 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: cp = "UNCONF_DN"; break;
Wayne Roberts 0:6b3ac9c5a042 1518 case FRAME_TYPE_DATA_CONFIRMED_UP: cp = "CONF_UP"; break;
Wayne Roberts 0:6b3ac9c5a042 1519 case FRAME_TYPE_DATA_CONFIRMED_DOWN: cp = "CONF_DN"; break;
Wayne Roberts 0:6b3ac9c5a042 1520 case FRAME_TYPE_PROPRIETARY: cp = "P"; break;
Wayne Roberts 0:6b3ac9c5a042 1521 default: return;
Wayne Roberts 0:6b3ac9c5a042 1522 }
Wayne Roberts 0:6b3ac9c5a042 1523 MAC_PRINTF("MTYPE_%s ", cp);
Wayne Roberts 0:6b3ac9c5a042 1524 #endif /* MAC_DEBUG */
Wayne Roberts 0:6b3ac9c5a042 1525 }
Wayne Roberts 0:6b3ac9c5a042 1526
Wayne Roberts 0:6b3ac9c5a042 1527 /* bool a: true=AFCntDown, false=NFCntDown */
Wayne Roberts 0:6b3ac9c5a042 1528 uint32_t get_fcntdwn(bool a)
Wayne Roberts 0:6b3ac9c5a042 1529 {
Wayne Roberts 0:6b3ac9c5a042 1530 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1531 if (a)
Wayne Roberts 0:6b3ac9c5a042 1532 return AFCntDown;
Wayne Roberts 0:6b3ac9c5a042 1533 else
Wayne Roberts 0:6b3ac9c5a042 1534 return NFCntDown;
Wayne Roberts 0:6b3ac9c5a042 1535 #else
Wayne Roberts 0:6b3ac9c5a042 1536 if (a)
Wayne Roberts 0:6b3ac9c5a042 1537 return eeprom_read(EEPROM_AFCNTDWN);
Wayne Roberts 0:6b3ac9c5a042 1538 else
Wayne Roberts 0:6b3ac9c5a042 1539 return eeprom_read(EEPROM_NFCNTDWN);
Wayne Roberts 0:6b3ac9c5a042 1540 #endif
Wayne Roberts 0:6b3ac9c5a042 1541 }
Wayne Roberts 0:6b3ac9c5a042 1542
Wayne Roberts 0:6b3ac9c5a042 1543 __attribute__((weak)) bool
Wayne Roberts 0:6b3ac9c5a042 1544 ProcessMacCommandsClassB(uint8_t* payload, uint8_t* macIndex)
Wayne Roberts 0:6b3ac9c5a042 1545 {
Wayne Roberts 0:6b3ac9c5a042 1546 return false; /* false: not taken */
Wayne Roberts 0:6b3ac9c5a042 1547 }
Wayne Roberts 0:6b3ac9c5a042 1548
Wayne Roberts 0:6b3ac9c5a042 1549
Wayne Roberts 0:6b3ac9c5a042 1550 static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask )
Wayne Roberts 0:6b3ac9c5a042 1551 {
Wayne Roberts 0:6b3ac9c5a042 1552 if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false )
Wayne Roberts 0:6b3ac9c5a042 1553 {
Wayne Roberts 0:6b3ac9c5a042 1554 return false;
Wayne Roberts 0:6b3ac9c5a042 1555 }
Wayne Roberts 0:6b3ac9c5a042 1556 for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
Wayne Roberts 0:6b3ac9c5a042 1557 {
Wayne Roberts 0:6b3ac9c5a042 1558 for( uint8_t j = 0; j < 16; j++ )
Wayne Roberts 0:6b3ac9c5a042 1559 {
Wayne Roberts 0:6b3ac9c5a042 1560 if( ( ( channelsMask[k] & ( 1 << j ) ) != 0 ) )
Wayne Roberts 0:6b3ac9c5a042 1561 {// Check datarate validity for enabled channels
Wayne Roberts 0:6b3ac9c5a042 1562 if( ValueInRange( datarate, Channels[i + j].DrRange.Fields.Min, Channels[i + j].DrRange.Fields.Max ) == true )
Wayne Roberts 0:6b3ac9c5a042 1563 {
Wayne Roberts 0:6b3ac9c5a042 1564 // At least 1 channel has been found we can return OK.
Wayne Roberts 0:6b3ac9c5a042 1565 return true;
Wayne Roberts 0:6b3ac9c5a042 1566 }
Wayne Roberts 0:6b3ac9c5a042 1567 }
Wayne Roberts 0:6b3ac9c5a042 1568 }
Wayne Roberts 0:6b3ac9c5a042 1569 }
Wayne Roberts 0:6b3ac9c5a042 1570 return false;
Wayne Roberts 0:6b3ac9c5a042 1571 }
Wayne Roberts 0:6b3ac9c5a042 1572
Wayne Roberts 0:6b3ac9c5a042 1573 static bool Rx2FreqInRange( uint32_t freq )
Wayne Roberts 0:6b3ac9c5a042 1574 {
Wayne Roberts 0:6b3ac9c5a042 1575 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) || defined (USE_BAND_ARIB_8CH)
Wayne Roberts 0:6b3ac9c5a042 1576 if( Radio::CheckRfFrequency( freq ) == true )
Wayne Roberts 0:6b3ac9c5a042 1577 #elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1578 if( ( Radio::CheckRfFrequency( freq ) == true ) &&
Wayne Roberts 0:6b3ac9c5a042 1579 ( freq >= LORAMAC_FIRST_RX1_CHANNEL ) &&
Wayne Roberts 0:6b3ac9c5a042 1580 ( freq <= LORAMAC_LAST_RX1_CHANNEL ) &&
Wayne Roberts 0:6b3ac9c5a042 1581 ( ( ( freq - ( uint32_t ) LORAMAC_FIRST_RX1_CHANNEL ) % ( uint32_t ) LORAMAC_STEPWIDTH_RX1_CHANNEL ) == 0 ) )
Wayne Roberts 0:6b3ac9c5a042 1582 #endif
Wayne Roberts 0:6b3ac9c5a042 1583 {
Wayne Roberts 0:6b3ac9c5a042 1584 return true;
Wayne Roberts 0:6b3ac9c5a042 1585 }
Wayne Roberts 0:6b3ac9c5a042 1586 return false;
Wayne Roberts 0:6b3ac9c5a042 1587 }
Wayne Roberts 0:6b3ac9c5a042 1588
Wayne Roberts 0:6b3ac9c5a042 1589 __attribute__((weak)) void
Wayne Roberts 0:6b3ac9c5a042 1590 deviceTimeClassB(uint32_t secs, uint32_t subsecs)
Wayne Roberts 0:6b3ac9c5a042 1591 {
Wayne Roberts 0:6b3ac9c5a042 1592 }
Wayne Roberts 0:6b3ac9c5a042 1593
Wayne Roberts 0:6b3ac9c5a042 1594 /* return -1 for unknown mac cmd */
Wayne Roberts 0:6b3ac9c5a042 1595 static int
Wayne Roberts 0:6b3ac9c5a042 1596 ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr, us_timestamp_t us_rxDone_at )
Wayne Roberts 0:6b3ac9c5a042 1597 {
Wayne Roberts 0:6b3ac9c5a042 1598 uint8_t buf[2];
Wayne Roberts 0:6b3ac9c5a042 1599 int ret = 0;
Wayne Roberts 0:6b3ac9c5a042 1600
Wayne Roberts 0:6b3ac9c5a042 1601 MACC_PRINTF("ProcessMacCommands(, %u, %u,,) ", macIndex, commandsSize);
Wayne Roberts 3:eb174e10afbb 1602 while (macIndex < commandsSize)
Wayne Roberts 0:6b3ac9c5a042 1603 {
Wayne Roberts 0:6b3ac9c5a042 1604 MACC_PRINTF("ProcessMacCommands %u(0x%02x): ", macIndex, payload[macIndex]);
Wayne Roberts 0:6b3ac9c5a042 1605 // Decode Frame MAC commands
Wayne Roberts 3:eb174e10afbb 1606 switch (payload[macIndex++])
Wayne Roberts 0:6b3ac9c5a042 1607 {
Wayne Roberts 0:6b3ac9c5a042 1608 case SRV_MAC_LINK_CHECK_ANS:
Wayne Roberts 0:6b3ac9c5a042 1609 MACC_PRINTF("LINK_CHECK_ANS ");
Wayne Roberts 0:6b3ac9c5a042 1610 buf[0] = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1611 buf[1] = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1612 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1613 MlmeConfirm.fields.link.DemodMargin = buf[0];
Wayne Roberts 0:6b3ac9c5a042 1614 MlmeConfirm.fields.link.NbGateways = buf[1];
Wayne Roberts 0:6b3ac9c5a042 1615 break;
Wayne Roberts 0:6b3ac9c5a042 1616 case SRV_MAC_LINK_ADR_REQ:
Wayne Roberts 0:6b3ac9c5a042 1617 MACC_PRINTF("LINK_ADR_REQ ");
Wayne Roberts 0:6b3ac9c5a042 1618 {
Wayne Roberts 0:6b3ac9c5a042 1619 uint8_t i;
Wayne Roberts 0:6b3ac9c5a042 1620 int8_t txPower = 0;
Wayne Roberts 0:6b3ac9c5a042 1621 uint8_t Redundancy = 0;
Wayne Roberts 0:6b3ac9c5a042 1622 adr_t adr;
Wayne Roberts 0:6b3ac9c5a042 1623
Wayne Roberts 0:6b3ac9c5a042 1624 adr.status = 0x07;
Wayne Roberts 0:6b3ac9c5a042 1625 // Initialize local copy of the channels mask array
Wayne Roberts 0:6b3ac9c5a042 1626 for( i = 0; i < 6; i++ )
Wayne Roberts 0:6b3ac9c5a042 1627 {
Wayne Roberts 0:6b3ac9c5a042 1628 adr.channelsMask[i] = LoRaMacParams.ChannelsMask[i];
Wayne Roberts 0:6b3ac9c5a042 1629 }
Wayne Roberts 0:6b3ac9c5a042 1630 adr.datarate = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1631 txPower = adr.datarate & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 1632 adr.datarate = ( adr.datarate >> 4 ) & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 1633 MACC_PRINTF("dr%u power%u ", adr.datarate, txPower);
Wayne Roberts 0:6b3ac9c5a042 1634
Wayne Roberts 0:6b3ac9c5a042 1635 if( ( flags.AdrCtrlOn == false ) &&
Wayne Roberts 0:6b3ac9c5a042 1636 ( ( LoRaMacParams.ChannelsDatarate != adr.datarate ) || ( LoRaMacParams.ChannelsTxPower != txPower ) ) )
Wayne Roberts 0:6b3ac9c5a042 1637 { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower
Wayne Roberts 0:6b3ac9c5a042 1638 MACC_PRINTF("AdrCtrlOn:%u dr%u != dr%u, %d != %d\r\n", flags.AdrCtrlOn,
Wayne Roberts 0:6b3ac9c5a042 1639 LoRaMacParams.ChannelsDatarate, adr.datarate,
Wayne Roberts 0:6b3ac9c5a042 1640 LoRaMacParams.ChannelsTxPower, txPower
Wayne Roberts 0:6b3ac9c5a042 1641 );
Wayne Roberts 0:6b3ac9c5a042 1642 // Answer the server with fail status
Wayne Roberts 0:6b3ac9c5a042 1643 // Power ACK = 0
Wayne Roberts 0:6b3ac9c5a042 1644 // Data rate ACK = 0
Wayne Roberts 0:6b3ac9c5a042 1645 // Channel mask = 0
Wayne Roberts 0:6b3ac9c5a042 1646 AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
Wayne Roberts 0:6b3ac9c5a042 1647 macIndex += 3; // Skip over the remaining bytes of the request
Wayne Roberts 0:6b3ac9c5a042 1648 break;
Wayne Roberts 0:6b3ac9c5a042 1649 }
Wayne Roberts 0:6b3ac9c5a042 1650 adr.chMask = ( uint16_t )payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1651 adr.chMask |= ( uint16_t )payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1652
Wayne Roberts 0:6b3ac9c5a042 1653 Redundancy = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1654 adr.chMaskCntl = ( Redundancy >> 4 ) & 0x07;
Wayne Roberts 3:eb174e10afbb 1655 if ((Redundancy & 0x0f) > 0)
Wayne Roberts 3:eb174e10afbb 1656 LoRaMacParams.NbTrans = Redundancy & 0x0f;
Wayne Roberts 0:6b3ac9c5a042 1657
Wayne Roberts 0:6b3ac9c5a042 1658 MACC_PRINTF("chMask:%04x chMaskCntl:%x nbTrans:%u ", adr.chMask, adr.chMaskCntl, LoRaMacParams.NbTrans);
Wayne Roberts 0:6b3ac9c5a042 1659
Wayne Roberts 0:6b3ac9c5a042 1660 region_adr_request(&adr);
Wayne Roberts 0:6b3ac9c5a042 1661
Wayne Roberts 0:6b3ac9c5a042 1662 if( ValidateDatarate( adr.datarate, adr.channelsMask ) == false )
Wayne Roberts 0:6b3ac9c5a042 1663 {
Wayne Roberts 0:6b3ac9c5a042 1664 MACC_PRINTF("badDr ");
Wayne Roberts 0:6b3ac9c5a042 1665 adr.status &= 0xFD; // Datarate KO
Wayne Roberts 0:6b3ac9c5a042 1666 }
Wayne Roberts 0:6b3ac9c5a042 1667
Wayne Roberts 0:6b3ac9c5a042 1668 //
Wayne Roberts 0:6b3ac9c5a042 1669 // Remark MaxTxPower = 0 and MinTxPower = 5
Wayne Roberts 0:6b3ac9c5a042 1670 //
Wayne Roberts 0:6b3ac9c5a042 1671 if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
Wayne Roberts 0:6b3ac9c5a042 1672 {
Wayne Roberts 0:6b3ac9c5a042 1673 MACC_PRINTF("badPower(max:%d given:%d min:%d) ", LORAMAC_MAX_TX_POWER, txPower, LORAMAC_MIN_TX_POWER);
Wayne Roberts 0:6b3ac9c5a042 1674 adr.status &= 0xFB; // TxPower KO
Wayne Roberts 0:6b3ac9c5a042 1675 }
Wayne Roberts 0:6b3ac9c5a042 1676 MACC_PRINTF("status:%x (idx %u) ", adr.status, macIndex);
Wayne Roberts 0:6b3ac9c5a042 1677 if( ( adr.status & 0x07 ) == 0x07 )
Wayne Roberts 0:6b3ac9c5a042 1678 {
Wayne Roberts 0:6b3ac9c5a042 1679 LoRaMacParams.ChannelsDatarate = adr.datarate;
Wayne Roberts 0:6b3ac9c5a042 1680 LoRaMacParams.ChannelsTxPower = txPower;
Wayne Roberts 0:6b3ac9c5a042 1681
Wayne Roberts 0:6b3ac9c5a042 1682 memcpy( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )adr.channelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
Wayne Roberts 3:eb174e10afbb 1683 LoRaMacParams.NbEnabledChannels = region_CountNbEnabledChannels();
Wayne Roberts 0:6b3ac9c5a042 1684
Wayne Roberts 0:6b3ac9c5a042 1685 }
Wayne Roberts 0:6b3ac9c5a042 1686 AddMacCommand( MOTE_MAC_LINK_ADR_ANS, adr.status, 0 );
Wayne Roberts 0:6b3ac9c5a042 1687 }
Wayne Roberts 0:6b3ac9c5a042 1688 break;
Wayne Roberts 0:6b3ac9c5a042 1689 case SRV_MAC_RX_PARAM_SETUP_REQ:
Wayne Roberts 0:6b3ac9c5a042 1690 {
Wayne Roberts 0:6b3ac9c5a042 1691 uint8_t status = 0x07;
Wayne Roberts 0:6b3ac9c5a042 1692 int8_t datarate = 0;
Wayne Roberts 0:6b3ac9c5a042 1693 int8_t drOffset = 0;
Wayne Roberts 0:6b3ac9c5a042 1694 uint32_t freq = 0;
Wayne Roberts 0:6b3ac9c5a042 1695
Wayne Roberts 0:6b3ac9c5a042 1696 drOffset = ( payload[macIndex] >> 4 ) & 0x07;
Wayne Roberts 0:6b3ac9c5a042 1697 datarate = payload[macIndex] & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 1698 macIndex++;
Wayne Roberts 0:6b3ac9c5a042 1699
Wayne Roberts 0:6b3ac9c5a042 1700 freq = ( uint32_t )payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1701 freq |= ( uint32_t )payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1702 freq |= ( uint32_t )payload[macIndex++] << 16;
Wayne Roberts 0:6b3ac9c5a042 1703 freq *= 100;
Wayne Roberts 0:6b3ac9c5a042 1704 MACC_PRINTF("RX_PARAM_SETUP_REQ %uhz drOffset:%u dr%u ", freq, drOffset, datarate);
Wayne Roberts 0:6b3ac9c5a042 1705
Wayne Roberts 0:6b3ac9c5a042 1706 if( Rx2FreqInRange( freq ) == false )
Wayne Roberts 0:6b3ac9c5a042 1707 {
Wayne Roberts 0:6b3ac9c5a042 1708 status &= 0xFE; // Channel frequency KO
Wayne Roberts 0:6b3ac9c5a042 1709 }
Wayne Roberts 0:6b3ac9c5a042 1710
Wayne Roberts 0:6b3ac9c5a042 1711 if( ValueInRange( datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE ) == false )
Wayne Roberts 0:6b3ac9c5a042 1712 {
Wayne Roberts 0:6b3ac9c5a042 1713 status &= 0xFD; // Datarate KO
Wayne Roberts 0:6b3ac9c5a042 1714 }
Wayne Roberts 0:6b3ac9c5a042 1715 #if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
Wayne Roberts 0:6b3ac9c5a042 1716 if( ( ValueInRange( datarate, DR_5, DR_7 ) == true ) ||
Wayne Roberts 0:6b3ac9c5a042 1717 ( datarate > DR_13 ) )
Wayne Roberts 0:6b3ac9c5a042 1718 {
Wayne Roberts 0:6b3ac9c5a042 1719 status &= 0xFD; // Datarate KO
Wayne Roberts 0:6b3ac9c5a042 1720 }
Wayne Roberts 0:6b3ac9c5a042 1721 #endif
Wayne Roberts 0:6b3ac9c5a042 1722 if( ValueInRange( drOffset, LORAMAC_MIN_RX1_DR_OFFSET, LORAMAC_MAX_RX1_DR_OFFSET ) == false )
Wayne Roberts 0:6b3ac9c5a042 1723 {
Wayne Roberts 0:6b3ac9c5a042 1724 status &= 0xFB; // Rx1DrOffset range KO
Wayne Roberts 0:6b3ac9c5a042 1725 }
Wayne Roberts 0:6b3ac9c5a042 1726
Wayne Roberts 0:6b3ac9c5a042 1727 MACC_PRINTF("status:0x%02x ", status);
Wayne Roberts 0:6b3ac9c5a042 1728 if( ( status & 0x07 ) == 0x07 )
Wayne Roberts 0:6b3ac9c5a042 1729 {
Wayne Roberts 0:6b3ac9c5a042 1730 LoRaMacParams.Rx2Channel.Datarate = datarate;
Wayne Roberts 0:6b3ac9c5a042 1731 LoRaMacParams.Rx2Channel.FrequencyHz = freq;
Wayne Roberts 0:6b3ac9c5a042 1732 LoRaMacParams.Rx1DrOffset = drOffset;
Wayne Roberts 0:6b3ac9c5a042 1733 }
Wayne Roberts 0:6b3ac9c5a042 1734 AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 );
Wayne Roberts 0:6b3ac9c5a042 1735 }
Wayne Roberts 0:6b3ac9c5a042 1736 break;
Wayne Roberts 0:6b3ac9c5a042 1737 case SRV_MAC_DEV_STATUS_REQ:
Wayne Roberts 0:6b3ac9c5a042 1738 MACC_PRINTF("DEV_STATUS_REQ ");
Wayne Roberts 0:6b3ac9c5a042 1739 {
Wayne Roberts 0:6b3ac9c5a042 1740 uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
Wayne Roberts 0:6b3ac9c5a042 1741 if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) )
Wayne Roberts 0:6b3ac9c5a042 1742 {
Wayne Roberts 0:6b3ac9c5a042 1743 batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
Wayne Roberts 0:6b3ac9c5a042 1744 }
Wayne Roberts 0:6b3ac9c5a042 1745 AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
Wayne Roberts 0:6b3ac9c5a042 1746 break;
Wayne Roberts 0:6b3ac9c5a042 1747 }
Wayne Roberts 0:6b3ac9c5a042 1748 case SRV_MAC_NEW_CHANNEL_REQ:
Wayne Roberts 0:6b3ac9c5a042 1749 {
Wayne Roberts 0:6b3ac9c5a042 1750 uint8_t status = 0x03;
Wayne Roberts 0:6b3ac9c5a042 1751
Wayne Roberts 0:6b3ac9c5a042 1752 #if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 1753 status &= 0xFC; // Channel frequency and datarate KO
Wayne Roberts 0:6b3ac9c5a042 1754 macIndex += 5;
Wayne Roberts 0:6b3ac9c5a042 1755 #else
Wayne Roberts 0:6b3ac9c5a042 1756 int8_t channelIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 1757 ChannelParams_t chParam;
Wayne Roberts 0:6b3ac9c5a042 1758
Wayne Roberts 0:6b3ac9c5a042 1759 channelIndex = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1760 chParam.FreqHz = ( uint32_t )payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1761 chParam.FreqHz |= ( uint32_t )payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1762 chParam.FreqHz |= ( uint32_t )payload[macIndex++] << 16;
Wayne Roberts 0:6b3ac9c5a042 1763 chParam.FreqHz *= 100;
Wayne Roberts 0:6b3ac9c5a042 1764 chParam.DrRange.Value = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1765 MACC_PRINTF("NEW_CHANNEL_REQ ch%u %uhz drRange:%02x ", channelIndex, chParam.Frequency, chParam.DrRange.Value);
Wayne Roberts 0:6b3ac9c5a042 1766
Wayne Roberts 0:6b3ac9c5a042 1767 if( chParam.FreqHz == 0 )
Wayne Roberts 0:6b3ac9c5a042 1768 {
Wayne Roberts 0:6b3ac9c5a042 1769 if( channelIndex < 3 )
Wayne Roberts 0:6b3ac9c5a042 1770 {
Wayne Roberts 0:6b3ac9c5a042 1771 status &= 0xFC;
Wayne Roberts 0:6b3ac9c5a042 1772 }
Wayne Roberts 0:6b3ac9c5a042 1773 else
Wayne Roberts 0:6b3ac9c5a042 1774 {
Wayne Roberts 0:6b3ac9c5a042 1775 if( LoRaMacChannelRemove( channelIndex ) != LORAMAC_STATUS_OK )
Wayne Roberts 0:6b3ac9c5a042 1776 {
Wayne Roberts 0:6b3ac9c5a042 1777 status &= 0xFC;
Wayne Roberts 0:6b3ac9c5a042 1778 }
Wayne Roberts 0:6b3ac9c5a042 1779 }
Wayne Roberts 0:6b3ac9c5a042 1780 }
Wayne Roberts 0:6b3ac9c5a042 1781 else
Wayne Roberts 0:6b3ac9c5a042 1782 {
Wayne Roberts 0:6b3ac9c5a042 1783 switch( LoRaMacChannelAdd( channelIndex, chParam ) )
Wayne Roberts 0:6b3ac9c5a042 1784 {
Wayne Roberts 0:6b3ac9c5a042 1785 case LORAMAC_STATUS_OK:
Wayne Roberts 0:6b3ac9c5a042 1786 {
Wayne Roberts 0:6b3ac9c5a042 1787 MACC_PRINTF("add-ok ");
Wayne Roberts 0:6b3ac9c5a042 1788 break;
Wayne Roberts 0:6b3ac9c5a042 1789 }
Wayne Roberts 0:6b3ac9c5a042 1790 case LORAMAC_STATUS_FREQUENCY_INVALID:
Wayne Roberts 0:6b3ac9c5a042 1791 {
Wayne Roberts 0:6b3ac9c5a042 1792 MACC_PRINTF("add-bad-freq ");
Wayne Roberts 0:6b3ac9c5a042 1793 status &= 0xFE;
Wayne Roberts 0:6b3ac9c5a042 1794 break;
Wayne Roberts 0:6b3ac9c5a042 1795 }
Wayne Roberts 0:6b3ac9c5a042 1796 case LORAMAC_STATUS_DATARATE_INVALID:
Wayne Roberts 0:6b3ac9c5a042 1797 {
Wayne Roberts 0:6b3ac9c5a042 1798 MACC_PRINTF("add-bad-dr ");
Wayne Roberts 0:6b3ac9c5a042 1799 status &= 0xFD;
Wayne Roberts 0:6b3ac9c5a042 1800 break;
Wayne Roberts 0:6b3ac9c5a042 1801 }
Wayne Roberts 0:6b3ac9c5a042 1802 case LORAMAC_STATUS_FREQ_AND_DR_INVALID:
Wayne Roberts 0:6b3ac9c5a042 1803 {
Wayne Roberts 0:6b3ac9c5a042 1804 MACC_PRINTF("add-bad-both ");
Wayne Roberts 0:6b3ac9c5a042 1805 status &= 0xFC;
Wayne Roberts 0:6b3ac9c5a042 1806 break;
Wayne Roberts 0:6b3ac9c5a042 1807 }
Wayne Roberts 0:6b3ac9c5a042 1808 default:
Wayne Roberts 0:6b3ac9c5a042 1809 {
Wayne Roberts 0:6b3ac9c5a042 1810 MACC_PRINTF("add-bad-? ");
Wayne Roberts 0:6b3ac9c5a042 1811 status &= 0xFC;
Wayne Roberts 0:6b3ac9c5a042 1812 break;
Wayne Roberts 0:6b3ac9c5a042 1813 }
Wayne Roberts 0:6b3ac9c5a042 1814 }
Wayne Roberts 0:6b3ac9c5a042 1815 }
Wayne Roberts 0:6b3ac9c5a042 1816 #endif
Wayne Roberts 0:6b3ac9c5a042 1817 MACC_PRINTF("status:%x ", status);
Wayne Roberts 0:6b3ac9c5a042 1818 AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
Wayne Roberts 0:6b3ac9c5a042 1819 }
Wayne Roberts 0:6b3ac9c5a042 1820 break;
Wayne Roberts 3:eb174e10afbb 1821 case SRV_MAC_ADR_PARAM_SETUP_REQ:
Wayne Roberts 3:eb174e10afbb 1822 MACC_PRINTF("ADR_PARAM_SETUP_REQ");
Wayne Roberts 3:eb174e10afbb 1823 {
Wayne Roberts 3:eb174e10afbb 1824 uint8_t exps = payload[macIndex++] & 0x0F;
Wayne Roberts 3:eb174e10afbb 1825 ADR_ACK_LIMIT = 1 << (exps >> 4);
Wayne Roberts 3:eb174e10afbb 1826 ADR_ACK_DELAY = 1 << (exps & 0x0f);
Wayne Roberts 3:eb174e10afbb 1827 }
Wayne Roberts 3:eb174e10afbb 1828 AddMacCommand(SRV_MAC_ADR_PARAM_SETUP_ANS, 0, 0);
Wayne Roberts 3:eb174e10afbb 1829 break;
Wayne Roberts 0:6b3ac9c5a042 1830 case SRV_MAC_RX_TIMING_SETUP_REQ:
Wayne Roberts 0:6b3ac9c5a042 1831 MACC_PRINTF("RX_TIMING_SETUP_REQ");
Wayne Roberts 0:6b3ac9c5a042 1832 {
Wayne Roberts 0:6b3ac9c5a042 1833 uint8_t delay = payload[macIndex++] & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 1834
Wayne Roberts 0:6b3ac9c5a042 1835 if( delay == 0 )
Wayne Roberts 0:6b3ac9c5a042 1836 {
Wayne Roberts 0:6b3ac9c5a042 1837 delay++;
Wayne Roberts 0:6b3ac9c5a042 1838 }
Wayne Roberts 0:6b3ac9c5a042 1839 LoRaMacParams.ReceiveDelay1_us = delay * 1e6;
Wayne Roberts 0:6b3ac9c5a042 1840 LoRaMacParams.ReceiveDelay2_us = LoRaMacParams.ReceiveDelay1_us + 1e6;
Wayne Roberts 0:6b3ac9c5a042 1841 AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
Wayne Roberts 0:6b3ac9c5a042 1842 }
Wayne Roberts 0:6b3ac9c5a042 1843 break;
Wayne Roberts 0:6b3ac9c5a042 1844 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 1845 case SRV_MAC_REKEY_CONF:
Wayne Roberts 3:eb174e10afbb 1846 macIndex++; //TODO server_version = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1847
Wayne Roberts 0:6b3ac9c5a042 1848 flags.need_ReKeyConf = 0;
Wayne Roberts 0:6b3ac9c5a042 1849 break;
Wayne Roberts 0:6b3ac9c5a042 1850 case SRV_MAC_FORCE_REJOIN_REQ:
Wayne Roberts 0:6b3ac9c5a042 1851 {
Wayne Roberts 0:6b3ac9c5a042 1852 uint16_t cmd_payload = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1853 cmd_payload |= payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1854 rejoin.type = (cmd_payload >> 4) & 7;
Wayne Roberts 0:6b3ac9c5a042 1855 if (rejoin.type == 2)
Wayne Roberts 0:6b3ac9c5a042 1856 JoinReqType = 2;
Wayne Roberts 0:6b3ac9c5a042 1857 else {
Wayne Roberts 0:6b3ac9c5a042 1858 JoinReqType = 0;
Wayne Roberts 0:6b3ac9c5a042 1859 rejoin.type = 0;
Wayne Roberts 0:6b3ac9c5a042 1860 }
Wayne Roberts 0:6b3ac9c5a042 1861
Wayne Roberts 0:6b3ac9c5a042 1862 rejoin.dr = cmd_payload & 0x0f;
Wayne Roberts 0:6b3ac9c5a042 1863 LoRaMacParams.ChannelsDatarate = rejoin.dr;
Wayne Roberts 0:6b3ac9c5a042 1864 rejoin.retries = 1 + ((cmd_payload >> 8) & 7);
Wayne Roberts 0:6b3ac9c5a042 1865 MAC_PRINTF("FORCE_REJOIN 0x%04x dr%u type%u tries%u ", cmd_payload, LoRaMacParams.ChannelsDatarate, JoinReqType, rejoin.retries);
Wayne Roberts 0:6b3ac9c5a042 1866
Wayne Roberts 0:6b3ac9c5a042 1867 {
Wayne Roberts 0:6b3ac9c5a042 1868 rejoin.Period = (cmd_payload >> 11) & 7;
Wayne Roberts 0:6b3ac9c5a042 1869 /* first forced-rejoin attempt must be immediate */
Wayne Roberts 0:6b3ac9c5a042 1870 rejoin.event.attach_us(_rejoin_retry, 50000);
Wayne Roberts 0:6b3ac9c5a042 1871 rejoin.forced = true;
Wayne Roberts 0:6b3ac9c5a042 1872 }
Wayne Roberts 0:6b3ac9c5a042 1873 }
Wayne Roberts 0:6b3ac9c5a042 1874 break;
Wayne Roberts 0:6b3ac9c5a042 1875 case SRV_MAC_REJOIN_PARAM_REQ:
Wayne Roberts 0:6b3ac9c5a042 1876 {
Wayne Roberts 0:6b3ac9c5a042 1877 uint8_t p = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1878 rejoin.type0.MaxTimeN = p >> 4;
Wayne Roberts 0:6b3ac9c5a042 1879 rejoin.type0.MaxCountN = p & 0xf;
Wayne Roberts 0:6b3ac9c5a042 1880 rejoin.type0.enabled = true;
Wayne Roberts 0:6b3ac9c5a042 1881 MACC_PRINTF("REJOIN_PARAM MaxTimeN%u MaxCountN%u ", rejoin.type0.MaxTimeN, rejoin.type0.MaxCountN);
Wayne Roberts 0:6b3ac9c5a042 1882 rejoin.type0.uplinks_since = 1 << (rejoin.type0.MaxCountN + 4);
Wayne Roberts 0:6b3ac9c5a042 1883 AddMacCommand(MOTE_MAC_REJOIN_PARAM_ANS, 0, 0);
Wayne Roberts 0:6b3ac9c5a042 1884 }
Wayne Roberts 0:6b3ac9c5a042 1885 break;
Wayne Roberts 0:6b3ac9c5a042 1886 #else
Wayne Roberts 0:6b3ac9c5a042 1887 case SRV_MAC_RESET_CONF:
Wayne Roberts 0:6b3ac9c5a042 1888 macIndex++; //TODO server_version = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1889 flags.need_ResetConf = 0;
Wayne Roberts 0:6b3ac9c5a042 1890 break;
Wayne Roberts 0:6b3ac9c5a042 1891 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 1892 case SRV_MAC_DEVICE_TIME_ANS:
Wayne Roberts 0:6b3ac9c5a042 1893 {
Wayne Roberts 0:6b3ac9c5a042 1894 uint32_t subusecs, secs;
Wayne Roberts 0:6b3ac9c5a042 1895 us_timestamp_t us_since_tx_done;
Wayne Roberts 0:6b3ac9c5a042 1896 secs = payload[macIndex++];
Wayne Roberts 0:6b3ac9c5a042 1897 secs += payload[macIndex++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1898 secs += payload[macIndex++] << 16;
Wayne Roberts 0:6b3ac9c5a042 1899 secs += payload[macIndex++] << 24;
Wayne Roberts 0:6b3ac9c5a042 1900 subusecs = payload[macIndex++] * 3906.5;
Wayne Roberts 0:6b3ac9c5a042 1901
Wayne Roberts 0:6b3ac9c5a042 1902 //MAC_PRINTF("secs:%u, subusecs:%u\r\n", secs, subusecs);
Wayne Roberts 0:6b3ac9c5a042 1903 deviceTimeClassB(secs, subusecs);
Wayne Roberts 0:6b3ac9c5a042 1904
Wayne Roberts 0:6b3ac9c5a042 1905 us_since_tx_done = Radio::lpt.read_us() - tx_done_at;
Wayne Roberts 0:6b3ac9c5a042 1906 MlmeConfirm.fields.time.uSeconds += us_since_tx_done;
Wayne Roberts 0:6b3ac9c5a042 1907 while (us_since_tx_done >= 1000000) {
Wayne Roberts 0:6b3ac9c5a042 1908 MlmeConfirm.fields.time.Seconds++;
Wayne Roberts 0:6b3ac9c5a042 1909 us_since_tx_done -= 1000000;
Wayne Roberts 0:6b3ac9c5a042 1910 }
Wayne Roberts 0:6b3ac9c5a042 1911 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 1912 MlmeConfirm.fields.time.Seconds = secs;
Wayne Roberts 0:6b3ac9c5a042 1913 MlmeConfirm.fields.time.uSeconds = subusecs;
Wayne Roberts 0:6b3ac9c5a042 1914 }
Wayne Roberts 0:6b3ac9c5a042 1915 break;
Wayne Roberts 0:6b3ac9c5a042 1916 default:
Wayne Roberts 0:6b3ac9c5a042 1917 --macIndex;
Wayne Roberts 0:6b3ac9c5a042 1918 if (ProcessMacCommandsClassB(payload, &macIndex)) {
Wayne Roberts 0:6b3ac9c5a042 1919 /* mac command was taken */
Wayne Roberts 0:6b3ac9c5a042 1920 //MACC_PRINTF("B-cont\r\n");
Wayne Roberts 0:6b3ac9c5a042 1921 }
Wayne Roberts 0:6b3ac9c5a042 1922 #ifdef DUTY_ENABLE
Wayne Roberts 0:6b3ac9c5a042 1923 else if (ProcessMacCommandsDuty(payload, &macIndex)) {
Wayne Roberts 0:6b3ac9c5a042 1924 /* mac command was taken */
Wayne Roberts 0:6b3ac9c5a042 1925 }
Wayne Roberts 0:6b3ac9c5a042 1926 #endif /* DUTY_ENABLE */
Wayne Roberts 0:6b3ac9c5a042 1927 else {
Wayne Roberts 0:6b3ac9c5a042 1928 ret = -1;
Wayne Roberts 0:6b3ac9c5a042 1929 MAC_PRINTF("unknown mac:0x%02x at %u\r\n", payload[macIndex-1], macIndex-1);
Wayne Roberts 0:6b3ac9c5a042 1930 }
Wayne Roberts 0:6b3ac9c5a042 1931 break;
Wayne Roberts 0:6b3ac9c5a042 1932 } // ..switch(payload[macIndex++])
Wayne Roberts 0:6b3ac9c5a042 1933
Wayne Roberts 0:6b3ac9c5a042 1934 MACC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 1935
Wayne Roberts 0:6b3ac9c5a042 1936 } // ..while( macIndex < commandsSize )
Wayne Roberts 0:6b3ac9c5a042 1937
Wayne Roberts 0:6b3ac9c5a042 1938 return ret;
Wayne Roberts 0:6b3ac9c5a042 1939 } // ..ProcessMacCommands()
Wayne Roberts 0:6b3ac9c5a042 1940
Wayne Roberts 0:6b3ac9c5a042 1941 #define MAX_FCNT_GAP 0x4000
Wayne Roberts 0:6b3ac9c5a042 1942 /* return: true == send downlink ack */
Wayne Roberts 0:6b3ac9c5a042 1943 static int
Wayne Roberts 0:6b3ac9c5a042 1944 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 1945 {
Wayne Roberts 0:6b3ac9c5a042 1946 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 1947 LoRaMacFrameCtrl_t fCtrl;
Wayne Roberts 0:6b3ac9c5a042 1948 uint32_t myFCntDwn32, rxFCnt32;
Wayne Roberts 0:6b3ac9c5a042 1949 uint8_t rxFPort;
Wayne Roberts 0:6b3ac9c5a042 1950 uint16_t rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 1951 uint32_t address;
Wayne Roberts 0:6b3ac9c5a042 1952 uint32_t mic, micRx;
Wayne Roberts 0:6b3ac9c5a042 1953 uint8_t appPayloadStartIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 1954 bool skipIndication = false;
Wayne Roberts 0:6b3ac9c5a042 1955 uint8_t frameLen = 0;
Wayne Roberts 0:6b3ac9c5a042 1956 bool is_AFCntDown;
Wayne Roberts 0:6b3ac9c5a042 1957 block_t block;
Wayne Roberts 0:6b3ac9c5a042 1958
Wayne Roberts 0:6b3ac9c5a042 1959 macHdr.Value = rx_payload[0];
Wayne Roberts 0:6b3ac9c5a042 1960
Wayne Roberts 0:6b3ac9c5a042 1961 address = rx_payload[pktHeaderLen++];
Wayne Roberts 0:6b3ac9c5a042 1962 address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 8 );
Wayne Roberts 0:6b3ac9c5a042 1963 address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 16 );
Wayne Roberts 0:6b3ac9c5a042 1964 address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 24 );
Wayne Roberts 0:6b3ac9c5a042 1965
Wayne Roberts 0:6b3ac9c5a042 1966 fCtrl.Value = rx_payload[pktHeaderLen++];
Wayne Roberts 0:6b3ac9c5a042 1967
Wayne Roberts 0:6b3ac9c5a042 1968 rxFCnt16 = ( uint16_t )rx_payload[pktHeaderLen++];
Wayne Roberts 0:6b3ac9c5a042 1969 rxFCnt16 |= ( uint16_t )rx_payload[pktHeaderLen++] << 8;
Wayne Roberts 0:6b3ac9c5a042 1970
Wayne Roberts 0:6b3ac9c5a042 1971 is_AFCntDown = false;
Wayne Roberts 0:6b3ac9c5a042 1972 if (( ( rx_size - 4 ) - (8 + fCtrl.Bits.FOptsLen) ) > 0) {
Wayne Roberts 0:6b3ac9c5a042 1973 appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
Wayne Roberts 0:6b3ac9c5a042 1974 rxFPort = rx_payload[appPayloadStartIndex++];
Wayne Roberts 0:6b3ac9c5a042 1975 if (flags.OptNeg && rxFPort > 0)
Wayne Roberts 0:6b3ac9c5a042 1976 is_AFCntDown = true;
Wayne Roberts 0:6b3ac9c5a042 1977 } /* else no payload/fport present */
Wayne Roberts 0:6b3ac9c5a042 1978
Wayne Roberts 0:6b3ac9c5a042 1979 myFCntDwn32 = get_fcntdwn(is_AFCntDown);
Wayne Roberts 0:6b3ac9c5a042 1980
Wayne Roberts 0:6b3ac9c5a042 1981 McpsIndication.expectedFCntDown = myFCntDwn32;
Wayne Roberts 0:6b3ac9c5a042 1982 McpsIndication.receivedFCntDown = rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 1983
Wayne Roberts 0:6b3ac9c5a042 1984 rxFCnt32 = (myFCntDwn32 & 0xffff0000) | rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 1985 DEBUG_MIC_DOWN(" rxFCnt32:%" PRIu32" ", rxFCnt32);
Wayne Roberts 0:6b3ac9c5a042 1986
Wayne Roberts 0:6b3ac9c5a042 1987 micRx = ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN];
Wayne Roberts 0:6b3ac9c5a042 1988 micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 1] << 8 );
Wayne Roberts 0:6b3ac9c5a042 1989 micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 2] << 16 );
Wayne Roberts 0:6b3ac9c5a042 1990 micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 3] << 24 );
Wayne Roberts 0:6b3ac9c5a042 1991
Wayne Roberts 0:6b3ac9c5a042 1992 block.b.header = 0x49;
Wayne Roberts 0:6b3ac9c5a042 1993 if (flags.OptNeg)
Wayne Roberts 0:6b3ac9c5a042 1994 block.b.confFCnt = ConfFCntUp;
Wayne Roberts 0:6b3ac9c5a042 1995 else
Wayne Roberts 0:6b3ac9c5a042 1996 block.b.confFCnt = 0;
Wayne Roberts 0:6b3ac9c5a042 1997 block.b.dr = 0;
Wayne Roberts 0:6b3ac9c5a042 1998 block.b.ch = 0;
Wayne Roberts 0:6b3ac9c5a042 1999 block.b.dir = DOWN_LINK;
Wayne Roberts 0:6b3ac9c5a042 2000 block.b.DevAddr = address;
Wayne Roberts 0:6b3ac9c5a042 2001 block.b.FCnt = rxFCnt32;
Wayne Roberts 0:6b3ac9c5a042 2002 block.b.zero8 = 0;
Wayne Roberts 0:6b3ac9c5a042 2003 block.b.lenMsg = rx_size - LORAMAC_MFR_LEN;
Wayne Roberts 0:6b3ac9c5a042 2004 mic = LoRaMacComputeMic(&block, rx_payload, keys.SNwkSIntKey);
Wayne Roberts 0:6b3ac9c5a042 2005 if (micRx != mic) {
Wayne Roberts 0:6b3ac9c5a042 2006 bool ignore_rx = true;
Wayne Roberts 3:eb174e10afbb 2007 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_MIC_FAIL);
Wayne Roberts 0:6b3ac9c5a042 2008 MAC_PRINTF("\e[31mmicFail");
Wayne Roberts 0:6b3ac9c5a042 2009 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2010 block.b.confFCnt = ConfFCntUp - 1;
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 3:eb174e10afbb 2014 else {
Wayne Roberts 0:6b3ac9c5a042 2015 block.b.confFCnt = 0;
Wayne Roberts 0:6b3ac9c5a042 2016 mic = LoRaMacComputeMic(&block, rx_payload, keys.SNwkSIntKey);
Wayne Roberts 3:eb174e10afbb 2017 if (micRx == mic)
Wayne Roberts 0:6b3ac9c5a042 2018 ignore_rx = false;
Wayne Roberts 0:6b3ac9c5a042 2019 }
Wayne Roberts 0:6b3ac9c5a042 2020 }
Wayne Roberts 0:6b3ac9c5a042 2021 if (ignore_rx) {
Wayne Roberts 0:6b3ac9c5a042 2022 MAC_PRINTF("\e[0m\r\n");
Wayne Roberts 0:6b3ac9c5a042 2023 return -1;
Wayne Roberts 0:6b3ac9c5a042 2024 } else {
Wayne Roberts 0:6b3ac9c5a042 2025 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
Wayne Roberts 0:6b3ac9c5a042 2026 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 2027 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
Wayne Roberts 0:6b3ac9c5a042 2028 }
Wayne Roberts 0:6b3ac9c5a042 2029 } else {
Wayne Roberts 0:6b3ac9c5a042 2030 /* downlink with good MIC means previous confirmed uplink was receied */
Wayne Roberts 0:6b3ac9c5a042 2031 ConfFCntUp = 0;
Wayne Roberts 0:6b3ac9c5a042 2032 if (McpsIndication.RxSlot == 1) // no need for RX2 with good mic on rx1
Wayne Roberts 0:6b3ac9c5a042 2033 RxWindowEvent2.detach();
Wayne Roberts 0:6b3ac9c5a042 2034 }
Wayne Roberts 0:6b3ac9c5a042 2035
Wayne Roberts 0:6b3ac9c5a042 2036 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2037 //McpsIndication.Multicast = 0;//multicast;
Wayne Roberts 0:6b3ac9c5a042 2038 McpsIndication.FramePending = fCtrl.Bits.FPending;
Wayne Roberts 0:6b3ac9c5a042 2039 McpsIndication.Buffer = NULL;
Wayne Roberts 0:6b3ac9c5a042 2040 McpsIndication.BufferSize = 0;
Wayne Roberts 0:6b3ac9c5a042 2041
Wayne Roberts 0:6b3ac9c5a042 2042 MacCommandsBufferToRepeatIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 2043
Wayne Roberts 0:6b3ac9c5a042 2044 if (macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN)
Wayne Roberts 0:6b3ac9c5a042 2045 {
Wayne Roberts 0:6b3ac9c5a042 2046 flags.SrvAckRequested = true;
Wayne Roberts 0:6b3ac9c5a042 2047 McpsIndication.McpsIndication = MCPS_CONFIRMED;
Wayne Roberts 0:6b3ac9c5a042 2048
Wayne Roberts 0:6b3ac9c5a042 2049 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2050 if (flags.IsLoRaMacNetworkJoined)
Wayne Roberts 0:6b3ac9c5a042 2051 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2052
Wayne Roberts 0:6b3ac9c5a042 2053 if (flags.OptNeg)
Wayne Roberts 0:6b3ac9c5a042 2054 ConfFCntDown = rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 2055 }
Wayne Roberts 0:6b3ac9c5a042 2056 else
Wayne Roberts 0:6b3ac9c5a042 2057 { // FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
Wayne Roberts 0:6b3ac9c5a042 2058 ConfFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 2059 flags.SrvAckRequested = false;
Wayne Roberts 0:6b3ac9c5a042 2060 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
Wayne Roberts 0:6b3ac9c5a042 2061 }
Wayne Roberts 0:6b3ac9c5a042 2062
Wayne Roberts 0:6b3ac9c5a042 2063 if (fCtrl.Bits.FOptsLen > 0)
Wayne Roberts 0:6b3ac9c5a042 2064 {
Wayne Roberts 0:6b3ac9c5a042 2065 // Decode Options field MAC commands
Wayne Roberts 0:6b3ac9c5a042 2066 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2067 uint32_t FCnt32;
Wayne Roberts 0:6b3ac9c5a042 2068 bool fromStored;
Wayne Roberts 0:6b3ac9c5a042 2069 uint8_t macDecrypt[16];
Wayne Roberts 0:6b3ac9c5a042 2070 DEBUG_CRYPT_BUF(keys.NwkSEncKey, 16, "NwkSEncKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2071 if (appPayloadStartIndex > 0) {
Wayne Roberts 0:6b3ac9c5a042 2072 /* rx header has AFCntDown: not for use with FOpts */
Wayne Roberts 0:6b3ac9c5a042 2073 FCnt32 = get_fcntdwn(false);
Wayne Roberts 0:6b3ac9c5a042 2074 fromStored = true;
Wayne Roberts 0:6b3ac9c5a042 2075 } else {
Wayne Roberts 0:6b3ac9c5a042 2076 /* NFCntDown received in rx header */
Wayne Roberts 0:6b3ac9c5a042 2077 FCnt32 = (get_fcntdwn(false) & 0xffff0000) | rxFCnt16;
Wayne Roberts 0:6b3ac9c5a042 2078 fromStored = false;
Wayne Roberts 0:6b3ac9c5a042 2079 }
Wayne Roberts 0:6b3ac9c5a042 2080 DEBUG_CRYPT("FCnt32:%" PRIu32" ", FCnt32);
Wayne Roberts 0:6b3ac9c5a042 2081 DEBUG_CRYPT_BUF(rx_payload+8, fCtrl.Bits.FOptsLen, "FOpts-rx", 0);
Wayne Roberts 0:6b3ac9c5a042 2082 LoRaMacEncrypt(0, rx_payload+8, fCtrl.Bits.FOptsLen, keys.NwkSEncKey, LoRaMacDevAddr, DOWN_LINK, FCnt32, macDecrypt);
Wayne Roberts 0:6b3ac9c5a042 2083 DEBUG_CRYPT_BUF(macDecrypt, fCtrl.Bits.FOptsLen, "FOpts-decrypt", 0);
Wayne Roberts 0:6b3ac9c5a042 2084 if (ProcessMacCommands(macDecrypt, 0, fCtrl.Bits.FOptsLen, snr, us_rxDone_at) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2085 if (fromStored) {
Wayne Roberts 0:6b3ac9c5a042 2086 MAC_PRINTF("fromStored-");
Wayne Roberts 0:6b3ac9c5a042 2087 }
Wayne Roberts 0:6b3ac9c5a042 2088 MAC_PRINTF("FCnt32:%lu ", FCnt32);
Wayne Roberts 0:6b3ac9c5a042 2089 }
Wayne Roberts 0:6b3ac9c5a042 2090 } else {
Wayne Roberts 0:6b3ac9c5a042 2091 MAC_PRINTF("ProcessMacCommands-FOpts ");
Wayne Roberts 0:6b3ac9c5a042 2092 ProcessMacCommands( rx_payload, 8, fCtrl.Bits.FOptsLen + 8, snr, us_rxDone_at );
Wayne Roberts 0:6b3ac9c5a042 2093 }
Wayne Roberts 0:6b3ac9c5a042 2094 }
Wayne Roberts 0:6b3ac9c5a042 2095
Wayne Roberts 0:6b3ac9c5a042 2096 if (appPayloadStartIndex > 0)
Wayne Roberts 0:6b3ac9c5a042 2097 {
Wayne Roberts 0:6b3ac9c5a042 2098 frameLen = ( rx_size - 4 ) - appPayloadStartIndex;
Wayne Roberts 0:6b3ac9c5a042 2099
Wayne Roberts 0:6b3ac9c5a042 2100 McpsIndication.Port = rxFPort;
Wayne Roberts 0:6b3ac9c5a042 2101
Wayne Roberts 0:6b3ac9c5a042 2102 if (rxFPort == 0)
Wayne Roberts 0:6b3ac9c5a042 2103 {
Wayne Roberts 0:6b3ac9c5a042 2104 if( ( fCtrl.Bits.FOptsLen == 0 ) /*&& ( multicast == 0 )*/ )
Wayne Roberts 0:6b3ac9c5a042 2105 {
Wayne Roberts 0:6b3ac9c5a042 2106 uint8_t macDecrypt[16];
Wayne Roberts 0:6b3ac9c5a042 2107 LoRaMacPayloadDecrypt(rx_payload + appPayloadStartIndex,
Wayne Roberts 0:6b3ac9c5a042 2108 frameLen,
Wayne Roberts 0:6b3ac9c5a042 2109 keys.NwkSEncKey,
Wayne Roberts 0:6b3ac9c5a042 2110 address,
Wayne Roberts 0:6b3ac9c5a042 2111 DOWN_LINK,
Wayne Roberts 0:6b3ac9c5a042 2112 rxFCnt32,
Wayne Roberts 0:6b3ac9c5a042 2113 macDecrypt
Wayne Roberts 0:6b3ac9c5a042 2114 );
Wayne Roberts 0:6b3ac9c5a042 2115
Wayne Roberts 0:6b3ac9c5a042 2116 // Decode frame payload MAC commands
Wayne Roberts 0:6b3ac9c5a042 2117 MAC_PRINTF("ProcessMacCommands-payload ");
Wayne Roberts 0:6b3ac9c5a042 2118 if (ProcessMacCommands( macDecrypt, 0, frameLen, snr, us_rxDone_at ) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2119 MAC_PRINTF(" rxFCnt32:%" PRIu32 " ", rxFCnt32);
Wayne Roberts 0:6b3ac9c5a042 2120 }
Wayne Roberts 0:6b3ac9c5a042 2121 }
Wayne Roberts 0:6b3ac9c5a042 2122 else
Wayne Roberts 0:6b3ac9c5a042 2123 {
Wayne Roberts 0:6b3ac9c5a042 2124 skipIndication = true;
Wayne Roberts 0:6b3ac9c5a042 2125 }
Wayne Roberts 0:6b3ac9c5a042 2126 }
Wayne Roberts 0:6b3ac9c5a042 2127 else
Wayne Roberts 0:6b3ac9c5a042 2128 { /* rxFPort > 0 */
Wayne Roberts 0:6b3ac9c5a042 2129 MAC_PRINTF("rxFCnt32:%" PRIu32" %08" PRIx32" ", rxFCnt32, address);
Wayne Roberts 0:6b3ac9c5a042 2130 MAC_PRINTF("FCntDown%" PRIu32 " ", rxFCnt32);
Wayne Roberts 0:6b3ac9c5a042 2131 DEBUG_CRYPT(" addr%" PRIx32" len%u\r\n", address, frameLen);
Wayne Roberts 0:6b3ac9c5a042 2132 DEBUG_CRYPT_BUF(rx_payload + appPayloadStartIndex, frameLen, "rxEncd", 0);
Wayne Roberts 0:6b3ac9c5a042 2133 DEBUG_CRYPT_BUF(keys.AppSKey, 16, "AppSKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2134 LoRaMacPayloadDecrypt(rx_payload + appPayloadStartIndex,
Wayne Roberts 0:6b3ac9c5a042 2135 frameLen,
Wayne Roberts 0:6b3ac9c5a042 2136 keys.AppSKey,
Wayne Roberts 0:6b3ac9c5a042 2137 address,
Wayne Roberts 0:6b3ac9c5a042 2138 DOWN_LINK,
Wayne Roberts 0:6b3ac9c5a042 2139 rxFCnt32,
Wayne Roberts 0:6b3ac9c5a042 2140 rxFRMPayload
Wayne Roberts 0:6b3ac9c5a042 2141 );
Wayne Roberts 0:6b3ac9c5a042 2142
Wayne Roberts 0:6b3ac9c5a042 2143 if( skipIndication == false )
Wayne Roberts 0:6b3ac9c5a042 2144 {
Wayne Roberts 0:6b3ac9c5a042 2145 McpsIndication.Buffer = rxFRMPayload;
Wayne Roberts 0:6b3ac9c5a042 2146 McpsIndication.BufferSize = frameLen;
Wayne Roberts 0:6b3ac9c5a042 2147 McpsIndication.RxData = true;
Wayne Roberts 0:6b3ac9c5a042 2148 }
Wayne Roberts 0:6b3ac9c5a042 2149 }
Wayne Roberts 0:6b3ac9c5a042 2150 } // ..if have payload
Wayne Roberts 0:6b3ac9c5a042 2151
Wayne Roberts 3:eb174e10afbb 2152 if (!skipIndication)
Wayne Roberts 0:6b3ac9c5a042 2153 {
Wayne Roberts 3:eb174e10afbb 2154 McpsIndication.AckReceived = fCtrl.Bits.Ack;
Wayne Roberts 3:eb174e10afbb 2155 McpsConfirm.AckReceived = fCtrl.Bits.Ack;
Wayne Roberts 0:6b3ac9c5a042 2156
Wayne Roberts 0:6b3ac9c5a042 2157 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 2158 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); // RxDone
Wayne Roberts 0:6b3ac9c5a042 2159 }
Wayne Roberts 0:6b3ac9c5a042 2160
Wayne Roberts 3:eb174e10afbb 2161 if (McpsIndication.RxSlot == 1 || McpsIndication.RxSlot == 2)
Wayne Roberts 3:eb174e10afbb 2162 McpsIndication.ADR_ACK_CNT = 0;
Wayne Roberts 3:eb174e10afbb 2163
Wayne Roberts 3:eb174e10afbb 2164 /* set FCntDwn to next expected value, if last NbTrans */
Wayne Roberts 0:6b3ac9c5a042 2165 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 3:eb174e10afbb 2166 if (flags.uplink_in_progress <= 1 && last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_UP) {
Wayne Roberts 0:6b3ac9c5a042 2167 if (fCtrl.Bits.Ack) {
Wayne Roberts 0:6b3ac9c5a042 2168 FCntUp++;
Wayne Roberts 0:6b3ac9c5a042 2169 } else {
Wayne Roberts 0:6b3ac9c5a042 2170 MAC_PRINTF("\e[31mrx-!ack\e[0m\n");
Wayne Roberts 0:6b3ac9c5a042 2171 }
Wayne Roberts 0:6b3ac9c5a042 2172 }
Wayne Roberts 0:6b3ac9c5a042 2173
Wayne Roberts 0:6b3ac9c5a042 2174 if (is_AFCntDown) {
Wayne Roberts 0:6b3ac9c5a042 2175 AFCntDown = rxFCnt32 + 1;
Wayne Roberts 0:6b3ac9c5a042 2176 } else {
Wayne Roberts 0:6b3ac9c5a042 2177 NFCntDown = rxFCnt32 + 1;
Wayne Roberts 0:6b3ac9c5a042 2178 }
Wayne Roberts 0:6b3ac9c5a042 2179 #else
Wayne Roberts 3:eb174e10afbb 2180 /* if last NbTrans confirmed uplink ack'd ok: increment FCntUp */
Wayne Roberts 3:eb174e10afbb 2181 if (flags.uplink_in_progress <= 1 && fCtrl.Bits.Ack && last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_UP) {
Wayne Roberts 0:6b3ac9c5a042 2182 eeprom_increment_value(EEPROM_FCNTUP); /* TODO handle ee-failure return */
Wayne Roberts 3:eb174e10afbb 2183 }
Wayne Roberts 0:6b3ac9c5a042 2184
Wayne Roberts 0:6b3ac9c5a042 2185 if (is_AFCntDown)
Wayne Roberts 0:6b3ac9c5a042 2186 eeprom_write_word(EEPROM_AFCNTDWN, rxFCnt32 + 1);
Wayne Roberts 0:6b3ac9c5a042 2187 else
Wayne Roberts 0:6b3ac9c5a042 2188 eeprom_write_word(EEPROM_NFCNTDWN, rxFCnt32 + 1);
Wayne Roberts 0:6b3ac9c5a042 2189 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2190
Wayne Roberts 0:6b3ac9c5a042 2191 return 0;
Wayne Roberts 0:6b3ac9c5a042 2192 } // ...rx_downlink()
Wayne Roberts 0:6b3ac9c5a042 2193
Wayne Roberts 0:6b3ac9c5a042 2194
Wayne Roberts 0:6b3ac9c5a042 2195 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2196 typedef union {
Wayne Roberts 0:6b3ac9c5a042 2197 struct {
Wayne Roberts 0:6b3ac9c5a042 2198 uint8_t mhdr;
Wayne Roberts 0:6b3ac9c5a042 2199 unsigned int joinNonce : 24;
Wayne Roberts 0:6b3ac9c5a042 2200 unsigned int Home_NetID : 24;
Wayne Roberts 0:6b3ac9c5a042 2201 uint32_t DevAddr;
Wayne Roberts 0:6b3ac9c5a042 2202 struct {
Wayne Roberts 0:6b3ac9c5a042 2203 uint8_t RX2dr : 4; // 0,1,2,3
Wayne Roberts 0:6b3ac9c5a042 2204 uint8_t RX1DRoffset : 3; // 4,5,6
Wayne Roberts 0:6b3ac9c5a042 2205 uint8_t OptNeg : 1; // 7
Wayne Roberts 0:6b3ac9c5a042 2206 } DLSettings;
Wayne Roberts 0:6b3ac9c5a042 2207 uint8_t RxDelay;
Wayne Roberts 0:6b3ac9c5a042 2208 } __attribute__((packed)) fields;
Wayne Roberts 0:6b3ac9c5a042 2209 uint8_t octets[13];
Wayne Roberts 0:6b3ac9c5a042 2210 } joinAccept_t;
Wayne Roberts 0:6b3ac9c5a042 2211 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2212
Wayne Roberts 0:6b3ac9c5a042 2213
Wayne Roberts 0:6b3ac9c5a042 2214 #define JOIN_ACCEPT_MAX_SIZE 34
Wayne Roberts 0:6b3ac9c5a042 2215 static void
Wayne Roberts 0:6b3ac9c5a042 2216 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 2217 {
Wayne Roberts 0:6b3ac9c5a042 2218 LoRaMacEventInfoStatus_t status = LORAMAC_EVENT_INFO_STATUS_UNKNOWN_MTYPE;
Wayne Roberts 0:6b3ac9c5a042 2219 LoRaMacHeader_t macHdr;
Wayne Roberts 0:6b3ac9c5a042 2220 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2221 uint8_t _jaDecrypted[JOIN_ACCEPT_MAX_SIZE];
Wayne Roberts 0:6b3ac9c5a042 2222 uint32_t mic, micRx;
Wayne Roberts 0:6b3ac9c5a042 2223 const uint8_t* key;
Wayne Roberts 0:6b3ac9c5a042 2224 const joinAccept_t* ja;
Wayne Roberts 0:6b3ac9c5a042 2225 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2226 uint8_t pktHeaderLen = 0;
Wayne Roberts 0:6b3ac9c5a042 2227
Wayne Roberts 0:6b3ac9c5a042 2228 McpsConfirm.AckReceived = false;
Wayne Roberts 0:6b3ac9c5a042 2229 McpsIndication.Rssi = rssi;
Wayne Roberts 0:6b3ac9c5a042 2230 McpsIndication.Snr = snr;
Wayne Roberts 0:6b3ac9c5a042 2231 McpsIndication.Port = 0;
Wayne Roberts 0:6b3ac9c5a042 2232 //McpsIndication.Multicast = 0;
Wayne Roberts 0:6b3ac9c5a042 2233 McpsIndication.FramePending = 0;
Wayne Roberts 0:6b3ac9c5a042 2234 McpsIndication.Buffer = NULL;
Wayne Roberts 0:6b3ac9c5a042 2235 McpsIndication.BufferSize = 0;
Wayne Roberts 0:6b3ac9c5a042 2236 McpsIndication.RxData = false;
Wayne Roberts 0:6b3ac9c5a042 2237 McpsIndication.AckReceived = false;
Wayne Roberts 0:6b3ac9c5a042 2238 McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
Wayne Roberts 0:6b3ac9c5a042 2239
Wayne Roberts 0:6b3ac9c5a042 2240 if (MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_SENDING) {
Wayne Roberts 0:6b3ac9c5a042 2241 /* when regular downlink is sent in response to rejoin request */
Wayne Roberts 0:6b3ac9c5a042 2242 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2243 }
Wayne Roberts 0:6b3ac9c5a042 2244
Wayne Roberts 0:6b3ac9c5a042 2245 if( LoRaMacDeviceClass != CLASS_C )
Wayne Roberts 0:6b3ac9c5a042 2246 {
Wayne Roberts 0:6b3ac9c5a042 2247 Radio::Sleep( );
Wayne Roberts 0:6b3ac9c5a042 2248 }
Wayne Roberts 0:6b3ac9c5a042 2249
Wayne Roberts 0:6b3ac9c5a042 2250 MAC_PRINTF("OnRadioRxDone(%u) RxSlot%d ", rx_size, McpsIndication.RxSlot);
Wayne Roberts 0:6b3ac9c5a042 2251 if (beacon_rx_done_payload(rx_payload, rx_size))
Wayne Roberts 0:6b3ac9c5a042 2252 return;
Wayne Roberts 0:6b3ac9c5a042 2253
Wayne Roberts 0:6b3ac9c5a042 2254 macHdr.Value = rx_payload[pktHeaderLen++];
Wayne Roberts 0:6b3ac9c5a042 2255
Wayne Roberts 0:6b3ac9c5a042 2256 MAC_PRINTF(" rx-");
Wayne Roberts 0:6b3ac9c5a042 2257 print_mtype(macHdr.Bits.MType);
Wayne Roberts 0:6b3ac9c5a042 2258 switch (macHdr.Bits.MType)
Wayne Roberts 0:6b3ac9c5a042 2259 {
Wayne Roberts 0:6b3ac9c5a042 2260 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2261 case FRAME_TYPE_JOIN_ACCEPT:
Wayne Roberts 0:6b3ac9c5a042 2262 /* always permitting join accept because it might be due to rejoin */
Wayne Roberts 0:6b3ac9c5a042 2263 if (rx_size >= JOIN_ACCEPT_MAX_SIZE) {
Wayne Roberts 0:6b3ac9c5a042 2264 printf("joinAccept overSize %u\r\n", rx_size);
Wayne Roberts 0:6b3ac9c5a042 2265 return;
Wayne Roberts 0:6b3ac9c5a042 2266 }
Wayne Roberts 0:6b3ac9c5a042 2267
Wayne Roberts 0:6b3ac9c5a042 2268 DEBUG_CRYPT_BUF(rx_payload, rx_size, "rxBuf", 0);
Wayne Roberts 0:6b3ac9c5a042 2269 MAC_PRINTF("JoinReqType:%02x ", JoinReqType);
Wayne Roberts 0:6b3ac9c5a042 2270 if (JoinReqType == 0xff) {
Wayne Roberts 0:6b3ac9c5a042 2271 DEBUG_CRYPT_BUF(RootNwkKey, 16, "NwkKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2272 key = RootNwkKey;
Wayne Roberts 0:6b3ac9c5a042 2273 } else {
Wayne Roberts 0:6b3ac9c5a042 2274 key = JSEncKey;
Wayne Roberts 0:6b3ac9c5a042 2275 DEBUG_CRYPT_BUF(JSEncKey, 16, "JSEncKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2276 }
Wayne Roberts 0:6b3ac9c5a042 2277 LoRaMacJoinDecrypt( rx_payload + 1, rx_size - 1, key, &_jaDecrypted[1]);
Wayne Roberts 0:6b3ac9c5a042 2278 DEBUG_CRYPT_BUF(_jaDecrypted, rx_size, "macbuf", 0);
Wayne Roberts 0:6b3ac9c5a042 2279
Wayne Roberts 0:6b3ac9c5a042 2280 _jaDecrypted[0] = macHdr.Value;
Wayne Roberts 0:6b3ac9c5a042 2281 ja = (joinAccept_t*)_jaDecrypted;
Wayne Roberts 0:6b3ac9c5a042 2282 flags.OptNeg = ja->fields.DLSettings.OptNeg;
Wayne Roberts 0:6b3ac9c5a042 2283
Wayne Roberts 0:6b3ac9c5a042 2284 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2285 uint8_t micBuf[40];
Wayne Roberts 0:6b3ac9c5a042 2286 uint8_t* ptr = micBuf;
Wayne Roberts 0:6b3ac9c5a042 2287 if (RootAppKey == NULL) {
Wayne Roberts 0:6b3ac9c5a042 2288 MAC_PRINTF("OptNeg-without-AppKey ");
Wayne Roberts 0:6b3ac9c5a042 2289 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_NO_APPKEY);
Wayne Roberts 0:6b3ac9c5a042 2290 return;
Wayne Roberts 0:6b3ac9c5a042 2291 }
Wayne Roberts 0:6b3ac9c5a042 2292 *ptr++ = JoinReqType;
Wayne Roberts 0:6b3ac9c5a042 2293 memcpyr(ptr, LoRaMacJoinEui, 8);
Wayne Roberts 0:6b3ac9c5a042 2294 ptr += 8;
Wayne Roberts 0:6b3ac9c5a042 2295 *ptr++ = LoRaMacDevNonce & 0xff;
Wayne Roberts 0:6b3ac9c5a042 2296 *ptr++ = LoRaMacDevNonce >> 8;
Wayne Roberts 0:6b3ac9c5a042 2297 memcpy(ptr, _jaDecrypted, rx_size - LORAMAC_MFR_LEN);
Wayne Roberts 0:6b3ac9c5a042 2298 ptr += rx_size - LORAMAC_MFR_LEN;
Wayne Roberts 0:6b3ac9c5a042 2299 DEBUG_MIC_BUF_DOWN(JSIntKey, 16, "JSIntKey", ROW_MIC);
Wayne Roberts 0:6b3ac9c5a042 2300 DEBUG_MIC_BUF_DOWN(micBuf, ptr - micBuf, "jaMic-in", ROW_MIC+1);
Wayne Roberts 0:6b3ac9c5a042 2301 if (LoRaMacJoinComputeMic(false, micBuf, ptr - micBuf, JSIntKey, &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 } else {
Wayne Roberts 0:6b3ac9c5a042 2306 if (LoRaMacJoinComputeMic(false, _jaDecrypted, rx_size - LORAMAC_MFR_LEN, RootNwkKey, &mic ) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2307 MAC_PRINTF("cryptFail\r\n");
Wayne Roberts 0:6b3ac9c5a042 2308 return;
Wayne Roberts 0:6b3ac9c5a042 2309 }
Wayne Roberts 0:6b3ac9c5a042 2310 }
Wayne Roberts 0:6b3ac9c5a042 2311
Wayne Roberts 0:6b3ac9c5a042 2312 micRx = ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN];
Wayne Roberts 0:6b3ac9c5a042 2313 micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 1] << 8 );
Wayne Roberts 0:6b3ac9c5a042 2314 micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 2] << 16 );
Wayne Roberts 0:6b3ac9c5a042 2315 micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 3] << 24 );
Wayne Roberts 0:6b3ac9c5a042 2316
Wayne Roberts 0:6b3ac9c5a042 2317 MAC_PRINTF("JOIN_ACCEPT %u,OptNeg%" PRIu32" ", rx_size, flags.OptNeg);
Wayne Roberts 0:6b3ac9c5a042 2318
Wayne Roberts 0:6b3ac9c5a042 2319 if (micRx == mic)
Wayne Roberts 0:6b3ac9c5a042 2320 {
Wayne Roberts 0:6b3ac9c5a042 2321 if (McpsIndication.RxSlot == 1) // no need for RX2 with good mic on rx1
Wayne Roberts 0:6b3ac9c5a042 2322 RxWindowEvent2.detach();
Wayne Roberts 0:6b3ac9c5a042 2323
Wayne Roberts 0:6b3ac9c5a042 2324 #ifdef LORAWAN_ROOT_APPKEY
Wayne Roberts 0:6b3ac9c5a042 2325 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2326 MlmeConfirm.fields.join.myJoinNonce = eeprom_read(EEPROM_JOINNONCE);
Wayne Roberts 0:6b3ac9c5a042 2327 MlmeConfirm.fields.join.rxJoinNonce = ja->fields.joinNonce;
Wayne Roberts 0:6b3ac9c5a042 2328 if (MlmeConfirm.fields.join.rxJoinNonce <= MlmeConfirm.fields.join.myJoinNonce) {
Wayne Roberts 0:6b3ac9c5a042 2329 /* replay attack */
Wayne Roberts 0:6b3ac9c5a042 2330 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_JOINNONCE);
Wayne Roberts 0:6b3ac9c5a042 2331 return;
Wayne Roberts 0:6b3ac9c5a042 2332 }
Wayne Roberts 0:6b3ac9c5a042 2333 flags.need_ReKeyConf = 1;
Wayne Roberts 0:6b3ac9c5a042 2334 LoRaMacJoinComputeSKeys_1v1( RootNwkKey, RootAppKey, _jaDecrypted+1, LoRaMacJoinEui, LoRaMacDevNonce, &keys);
Wayne Roberts 0:6b3ac9c5a042 2335 eeprom_write_word(EEPROM_JOINNONCE, MlmeConfirm.fields.join.rxJoinNonce);
Wayne Roberts 0:6b3ac9c5a042 2336 } else
Wayne Roberts 0:6b3ac9c5a042 2337 #endif /* LORAWAN_ROOT_APPKEY */
Wayne Roberts 0:6b3ac9c5a042 2338 LoRaMacJoinComputeSKeys_1v0( RootNwkKey, _jaDecrypted+1, LoRaMacDevNonce, &keys);
Wayne Roberts 0:6b3ac9c5a042 2339
Wayne Roberts 0:6b3ac9c5a042 2340 DEBUG_CRYPT_BUF(keys.AppSKey , 16, "create-AppSKey", 0);
Wayne Roberts 0:6b3ac9c5a042 2341
Wayne Roberts 0:6b3ac9c5a042 2342 LoRaMacNetID = ja->fields.Home_NetID;
Wayne Roberts 0:6b3ac9c5a042 2343 LoRaMacDevAddr = ja->fields.DevAddr;
Wayne Roberts 0:6b3ac9c5a042 2344
Wayne Roberts 0:6b3ac9c5a042 2345 // DLSettings
Wayne Roberts 0:6b3ac9c5a042 2346 LoRaMacParams.Rx1DrOffset = ja->fields.DLSettings.RX1DRoffset;
Wayne Roberts 0:6b3ac9c5a042 2347 LoRaMacParams.Rx2Channel.Datarate = ja->fields.DLSettings.RX2dr;
Wayne Roberts 0:6b3ac9c5a042 2348
Wayne Roberts 0:6b3ac9c5a042 2349 // RxDelay
Wayne Roberts 0:6b3ac9c5a042 2350 LoRaMacParams.ReceiveDelay1_us = (ja->fields.RxDelay & 0x0f) * 1000000;
Wayne Roberts 0:6b3ac9c5a042 2351 if( LoRaMacParams.ReceiveDelay1_us == 0 )
Wayne Roberts 0:6b3ac9c5a042 2352 {
Wayne Roberts 0:6b3ac9c5a042 2353 LoRaMacParams.ReceiveDelay1_us = 1000000;
Wayne Roberts 0:6b3ac9c5a042 2354 }
Wayne Roberts 0:6b3ac9c5a042 2355 LoRaMacParams.ReceiveDelay2_us = LoRaMacParams.ReceiveDelay1_us + 1000000;
Wayne Roberts 0:6b3ac9c5a042 2356 MAC_PRINTF("rx1droffset:%u, rx2dr%u rxDelays:%" PRIu32" %" PRIu32", devaddr:%08" PRIx32" ",
Wayne Roberts 0:6b3ac9c5a042 2357 LoRaMacParams.Rx1DrOffset,
Wayne Roberts 0:6b3ac9c5a042 2358 LoRaMacParams.Rx2Channel.Datarate,
Wayne Roberts 0:6b3ac9c5a042 2359 LoRaMacParams.ReceiveDelay1_us,
Wayne Roberts 0:6b3ac9c5a042 2360 LoRaMacParams.ReceiveDelay2_us,
Wayne Roberts 0:6b3ac9c5a042 2361 LoRaMacDevAddr
Wayne Roberts 0:6b3ac9c5a042 2362 );
Wayne Roberts 0:6b3ac9c5a042 2363
Wayne Roberts 0:6b3ac9c5a042 2364 #if !( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) // TODO
Wayne Roberts 0:6b3ac9c5a042 2365 //CFList
Wayne Roberts 0:6b3ac9c5a042 2366 if( ( rx_size - 1 ) > 16 )
Wayne Roberts 0:6b3ac9c5a042 2367 {
Wayne Roberts 0:6b3ac9c5a042 2368 ChannelParams_t param;
Wayne Roberts 0:6b3ac9c5a042 2369 param.DrRange.Value = ( LORAMAC_TX_MAX_DATARATE << 4 ) | LORAMAC_TX_MIN_DATARATE;
Wayne Roberts 0:6b3ac9c5a042 2370
Wayne Roberts 0:6b3ac9c5a042 2371 for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 )
Wayne Roberts 0:6b3ac9c5a042 2372 {
Wayne Roberts 0:6b3ac9c5a042 2373 param.FreqHz = ( ( uint32_t )_jaDecrypted[13 + j] | ( ( uint32_t )_jaDecrypted[14 + j] << 8 ) | ( ( uint32_t )_jaDecrypted[15 + j] << 16 ) ) * 100;
Wayne Roberts 0:6b3ac9c5a042 2374 if( param.FreqHz != 0 )
Wayne Roberts 0:6b3ac9c5a042 2375 {
Wayne Roberts 0:6b3ac9c5a042 2376 LoRaMacChannelAdd( i, param );
Wayne Roberts 0:6b3ac9c5a042 2377 }
Wayne Roberts 0:6b3ac9c5a042 2378 else
Wayne Roberts 0:6b3ac9c5a042 2379 {
Wayne Roberts 0:6b3ac9c5a042 2380 LoRaMacChannelRemove( i );
Wayne Roberts 0:6b3ac9c5a042 2381 }
Wayne Roberts 0:6b3ac9c5a042 2382 }
Wayne Roberts 0:6b3ac9c5a042 2383 }
Wayne Roberts 0:6b3ac9c5a042 2384 #endif
Wayne Roberts 0:6b3ac9c5a042 2385 status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2386 flags.IsLoRaMacNetworkJoined = true;
Wayne Roberts 0:6b3ac9c5a042 2387 LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 2388
Wayne Roberts 0:6b3ac9c5a042 2389 MAC_PRINTF("JoinReqType%x\r\n", JoinReqType);
Wayne Roberts 0:6b3ac9c5a042 2390 FCntUp = 0;
Wayne Roberts 0:6b3ac9c5a042 2391 NFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 2392 AFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 2393 ConfFCntDown = 0;
Wayne Roberts 0:6b3ac9c5a042 2394 RJcount0 = 0;
Wayne Roberts 3:eb174e10afbb 2395 McpsIndication.ADR_ACK_CNT = 0;
Wayne Roberts 0:6b3ac9c5a042 2396
Wayne Roberts 0:6b3ac9c5a042 2397 rejoin.event.detach();
Wayne Roberts 0:6b3ac9c5a042 2398
Wayne Roberts 0:6b3ac9c5a042 2399 // must always notify application layer
Wayne Roberts 0:6b3ac9c5a042 2400 MlmeConfirm.MlmeRequest = MLME_JOIN;
Wayne Roberts 0:6b3ac9c5a042 2401 region_session_start(LORAMAC_EVENT_INFO_STATUS_OK);
Wayne Roberts 0:6b3ac9c5a042 2402 }
Wayne Roberts 0:6b3ac9c5a042 2403 else
Wayne Roberts 0:6b3ac9c5a042 2404 { /* join-accept mic fail */
Wayne Roberts 0:6b3ac9c5a042 2405 status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
dudmuck 2:c9c736b3e4eb 2406 MAC_PRINTF("ja-mic-fail rx:%" PRIx32 " calc:%" PRIx32" size:%d\r\n", micRx, mic, rx_size);
Wayne Roberts 0:6b3ac9c5a042 2407 if (MlmeIndication.MlmeIndication != MLME_NONE) {
dudmuck 2:c9c736b3e4eb 2408 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
Wayne Roberts 0:6b3ac9c5a042 2409 if (LoRaMacPrimitives->MacMlmeIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 2410 LoRaMacPrimitives->MacMlmeIndication(&MlmeIndication);
Wayne Roberts 0:6b3ac9c5a042 2411 }
Wayne Roberts 0:6b3ac9c5a042 2412 }
Wayne Roberts 0:6b3ac9c5a042 2413 break;
Wayne Roberts 0:6b3ac9c5a042 2414 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2415 case FRAME_TYPE_DATA_CONFIRMED_DOWN:
Wayne Roberts 0:6b3ac9c5a042 2416 case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
Wayne Roberts 0:6b3ac9c5a042 2417 if (rx_downlink(pktHeaderLen, rx_payload, rx_size, snr, us_rxDone_at) == 0)
Wayne Roberts 0:6b3ac9c5a042 2418 status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2419 break;
Wayne Roberts 0:6b3ac9c5a042 2420 case FRAME_TYPE_PROPRIETARY:
Wayne Roberts 0:6b3ac9c5a042 2421 {
Wayne Roberts 0:6b3ac9c5a042 2422 McpsIndication.McpsIndication = MCPS_PROPRIETARY;
Wayne Roberts 0:6b3ac9c5a042 2423 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2424 McpsIndication.Buffer = Radio::radio.rx_buf;
Wayne Roberts 0:6b3ac9c5a042 2425 McpsIndication.BufferSize = rx_size - pktHeaderLen;
Wayne Roberts 0:6b3ac9c5a042 2426
Wayne Roberts 0:6b3ac9c5a042 2427 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
Wayne Roberts 0:6b3ac9c5a042 2428 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); // RxDone
Wayne Roberts 0:6b3ac9c5a042 2429 break;
Wayne Roberts 0:6b3ac9c5a042 2430 }
Wayne Roberts 0:6b3ac9c5a042 2431 default:
Wayne Roberts 0:6b3ac9c5a042 2432 MAC_PRINTF("unknown frame type:%02x\r\n", macHdr.Value);
Wayne Roberts 0:6b3ac9c5a042 2433 PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_UNKNOWN_MTYPE);
Wayne Roberts 0:6b3ac9c5a042 2434 break;
Wayne Roberts 0:6b3ac9c5a042 2435 } // ..switch( macHdr.Bits.MType )
Wayne Roberts 0:6b3ac9c5a042 2436
Wayne Roberts 0:6b3ac9c5a042 2437 if (LoRaMacDeviceClass == CLASS_C) {
Wayne Roberts 0:6b3ac9c5a042 2438 if (McpsIndication.RxSlot == 1) {
Wayne Roberts 0:6b3ac9c5a042 2439 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 2440 RxWindow2Start(); // immiediately to continuous rx2 reception
Wayne Roberts 0:6b3ac9c5a042 2441 McpsIndication.RxSlot = 2;
Wayne Roberts 0:6b3ac9c5a042 2442 }
Wayne Roberts 0:6b3ac9c5a042 2443 }
Wayne Roberts 0:6b3ac9c5a042 2444
Wayne Roberts 0:6b3ac9c5a042 2445 {
Wayne Roberts 0:6b3ac9c5a042 2446 finish_uplink(status);
Wayne Roberts 0:6b3ac9c5a042 2447
Wayne Roberts 0:6b3ac9c5a042 2448 mcps_confirm(status); // RxDone
Wayne Roberts 0:6b3ac9c5a042 2449 mlme_confirm(status);
Wayne Roberts 0:6b3ac9c5a042 2450 }
Wayne Roberts 0:6b3ac9c5a042 2451
Wayne Roberts 0:6b3ac9c5a042 2452 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 2453
Wayne Roberts 0:6b3ac9c5a042 2454 flags.rxing = false;
Wayne Roberts 0:6b3ac9c5a042 2455 } // ..OnRadioRxDone()
Wayne Roberts 0:6b3ac9c5a042 2456
Wayne Roberts 0:6b3ac9c5a042 2457 __attribute__((weak)) bool
Wayne Roberts 0:6b3ac9c5a042 2458 beacon_rx_timeout()
Wayne Roberts 0:6b3ac9c5a042 2459 {
Wayne Roberts 0:6b3ac9c5a042 2460 return false;
Wayne Roberts 0:6b3ac9c5a042 2461 }
Wayne Roberts 0:6b3ac9c5a042 2462
Wayne Roberts 0:6b3ac9c5a042 2463 void OnRadioRxTimeout( void )
Wayne Roberts 0:6b3ac9c5a042 2464 {
Wayne Roberts 0:6b3ac9c5a042 2465 MAC_PRINTF("OnRadioRxTimeout()%d ", McpsIndication.RxSlot);
Wayne Roberts 0:6b3ac9c5a042 2466 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2467 MAC_PRINTF(",%u ", flags.IsLoRaMacNetworkJoined);
Wayne Roberts 0:6b3ac9c5a042 2468 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2469
Wayne Roberts 0:6b3ac9c5a042 2470 if (beacon_rx_timeout())
Wayne Roberts 0:6b3ac9c5a042 2471 return;
Wayne Roberts 0:6b3ac9c5a042 2472
Wayne Roberts 0:6b3ac9c5a042 2473 if (McpsIndication.RxSlot == 1)
Wayne Roberts 0:6b3ac9c5a042 2474 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 2475
Wayne Roberts 0:6b3ac9c5a042 2476 if (LoRaMacDeviceClass == CLASS_C)
Wayne Roberts 0:6b3ac9c5a042 2477 RxWindow2Start();
Wayne Roberts 0:6b3ac9c5a042 2478 else
Wayne Roberts 0:6b3ac9c5a042 2479 Radio::Sleep( );
Wayne Roberts 0:6b3ac9c5a042 2480
Wayne Roberts 0:6b3ac9c5a042 2481 if (McpsIndication.RxSlot == 2)
Wayne Roberts 0:6b3ac9c5a042 2482 {
Wayne Roberts 0:6b3ac9c5a042 2483 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2484 if (flags.IsLoRaMacNetworkJoined) {
Wayne Roberts 0:6b3ac9c5a042 2485 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2486 if (uplinkMHDR->Bits.MType == FRAME_TYPE_DATA_UNCONFIRMED_UP) {
Wayne Roberts 0:6b3ac9c5a042 2487 /* sent once, stoping now */
Wayne Roberts 0:6b3ac9c5a042 2488 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 2489 }
Wayne Roberts 0:6b3ac9c5a042 2490
Wayne Roberts 0:6b3ac9c5a042 2491 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 2492 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2493 } else {
Wayne Roberts 0:6b3ac9c5a042 2494 if (++MlmeIndication.JoinRequestTrials < MaxJoinRequestTrials) {
Wayne Roberts 4:e4bfe9183f94 2495 TxDelayedEvent.attach_us(OnTxDelayedIsr, 1000000);
Wayne Roberts 0:6b3ac9c5a042 2496 MAC_PRINTF("RxTImeout-join-tx-delay\r\n");
Wayne Roberts 0:6b3ac9c5a042 2497 MAC_PRINTF("join-try%u of%u ", MlmeIndication.JoinRequestTrials, MaxJoinRequestTrials);
Wayne Roberts 0:6b3ac9c5a042 2498
Wayne Roberts 0:6b3ac9c5a042 2499 if (MlmeIndication.MlmeIndication != MLME_NONE) {
Wayne Roberts 0:6b3ac9c5a042 2500 MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
Wayne Roberts 0:6b3ac9c5a042 2501 if (LoRaMacPrimitives->MacMlmeIndication)
Wayne Roberts 0:6b3ac9c5a042 2502 LoRaMacPrimitives->MacMlmeIndication(&MlmeIndication);
Wayne Roberts 0:6b3ac9c5a042 2503 }
Wayne Roberts 0:6b3ac9c5a042 2504 } else {
Wayne Roberts 0:6b3ac9c5a042 2505 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL);
Wayne Roberts 0:6b3ac9c5a042 2506 }
Wayne Roberts 0:6b3ac9c5a042 2507 }
Wayne Roberts 0:6b3ac9c5a042 2508 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2509
Wayne Roberts 0:6b3ac9c5a042 2510 finish_uplink(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
Wayne Roberts 0:6b3ac9c5a042 2511 } // ..if (McpsIndication.RxSlot == 2)
Wayne Roberts 0:6b3ac9c5a042 2512 MAC_PRINTF("\r\n");
Wayne Roberts 0:6b3ac9c5a042 2513
Wayne Roberts 0:6b3ac9c5a042 2514 flags.rxing = false;
Wayne Roberts 0:6b3ac9c5a042 2515
Wayne Roberts 0:6b3ac9c5a042 2516 } // ..OnRadioRxTimeout()
Wayne Roberts 0:6b3ac9c5a042 2517
Wayne Roberts 0:6b3ac9c5a042 2518 __attribute__((weak)) void
Wayne Roberts 0:6b3ac9c5a042 2519 on_dio0_top_half(us_timestamp_t dio0_at)
Wayne Roberts 0:6b3ac9c5a042 2520 {
Wayne Roberts 0:6b3ac9c5a042 2521 }
Wayne Roberts 0:6b3ac9c5a042 2522
Wayne Roberts 0:6b3ac9c5a042 2523 static void OnRadioRxError( void )
Wayne Roberts 0:6b3ac9c5a042 2524 {
Wayne Roberts 0:6b3ac9c5a042 2525 if( LoRaMacDeviceClass != CLASS_C )
Wayne Roberts 0:6b3ac9c5a042 2526 {
Wayne Roberts 0:6b3ac9c5a042 2527 Radio::Sleep( );
Wayne Roberts 0:6b3ac9c5a042 2528 }
Wayne Roberts 0:6b3ac9c5a042 2529 else
Wayne Roberts 0:6b3ac9c5a042 2530 {
Wayne Roberts 0:6b3ac9c5a042 2531 RxWindow2Setup();
Wayne Roberts 0:6b3ac9c5a042 2532 RxWindow2Start();
Wayne Roberts 0:6b3ac9c5a042 2533 }
Wayne Roberts 0:6b3ac9c5a042 2534
Wayne Roberts 0:6b3ac9c5a042 2535 if (McpsIndication.RxSlot == 2)
Wayne Roberts 0:6b3ac9c5a042 2536 {
Wayne Roberts 0:6b3ac9c5a042 2537 flags.uplink_in_progress = 0; // TODO check
Wayne Roberts 0:6b3ac9c5a042 2538 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_ERROR);
Wayne Roberts 0:6b3ac9c5a042 2539 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_ERROR);
Wayne Roberts 0:6b3ac9c5a042 2540 }
Wayne Roberts 0:6b3ac9c5a042 2541 } // ..OnRadioRxError
Wayne Roberts 0:6b3ac9c5a042 2542
Wayne Roberts 0:6b3ac9c5a042 2543 const RadioEvents_t RadioEvents = {
Wayne Roberts 0:6b3ac9c5a042 2544 /* Dio0_top_half */ on_dio0_top_half,
Wayne Roberts 0:6b3ac9c5a042 2545 /* TxDone */ OnRadioTxDone,
Wayne Roberts 0:6b3ac9c5a042 2546 /* TxTimeout */ OnRadioTxTimeout,
Wayne Roberts 0:6b3ac9c5a042 2547 /* RxDone */ OnRadioRxDone,
Wayne Roberts 0:6b3ac9c5a042 2548 /* RxTimeout */ OnRadioRxTimeout,
Wayne Roberts 0:6b3ac9c5a042 2549 /* RxError */ OnRadioRxError,
Wayne Roberts 0:6b3ac9c5a042 2550 /* FhssChangeChannel */ NULL,
Wayne Roberts 0:6b3ac9c5a042 2551 /* CadDone */ NULL
Wayne Roberts 0:6b3ac9c5a042 2552 };
Wayne Roberts 0:6b3ac9c5a042 2553
dudmuck 2:c9c736b3e4eb 2554
Wayne Roberts 0:6b3ac9c5a042 2555 LoRaMacStatus_t
Wayne Roberts 0:6b3ac9c5a042 2556 LoRaMacInitialization( const LoRaMacPrimitives_t *primitives, const LoRaMacCallback_t *callbacks )
Wayne Roberts 0:6b3ac9c5a042 2557 {
Wayne Roberts 0:6b3ac9c5a042 2558 if( primitives == NULL )
Wayne Roberts 0:6b3ac9c5a042 2559 {
Wayne Roberts 0:6b3ac9c5a042 2560 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 2561 }
Wayne Roberts 0:6b3ac9c5a042 2562
Wayne Roberts 0:6b3ac9c5a042 2563 if( ( primitives->MacMcpsConfirm == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 2564 ( primitives->MacMcpsIndication == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 2565 ( primitives->MacMlmeConfirm == NULL ) ||
Wayne Roberts 0:6b3ac9c5a042 2566 ( primitives->MacMlmeIndication == NULL ) )
Wayne Roberts 0:6b3ac9c5a042 2567 {
Wayne Roberts 0:6b3ac9c5a042 2568 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 2569 }
Wayne Roberts 0:6b3ac9c5a042 2570
dudmuck 2:c9c736b3e4eb 2571 if (targetCheckLSE() < 0)
dudmuck 2:c9c736b3e4eb 2572 return LORAMAC_STATUS_LSE;
Wayne Roberts 0:6b3ac9c5a042 2573
Wayne Roberts 0:6b3ac9c5a042 2574 LoRaMacPrimitives = primitives;
Wayne Roberts 0:6b3ac9c5a042 2575 LoRaMacCallbacks = callbacks;
Wayne Roberts 0:6b3ac9c5a042 2576
Wayne Roberts 0:6b3ac9c5a042 2577 LoRaMacDeviceClass = CLASS_A;
Wayne Roberts 0:6b3ac9c5a042 2578
Wayne Roberts 0:6b3ac9c5a042 2579 #ifdef DUTY_ENABLE
Wayne Roberts 0:6b3ac9c5a042 2580 DutyInit();
Wayne Roberts 0:6b3ac9c5a042 2581 #endif /* DUTY_ENABLE */
Wayne Roberts 0:6b3ac9c5a042 2582
Wayne Roberts 0:6b3ac9c5a042 2583 region_mac_init();
Wayne Roberts 0:6b3ac9c5a042 2584
Wayne Roberts 0:6b3ac9c5a042 2585 ResetMacParameters( );
Wayne Roberts 0:6b3ac9c5a042 2586
Wayne Roberts 0:6b3ac9c5a042 2587 // Initialize Radio driver
Wayne Roberts 0:6b3ac9c5a042 2588
Wayne Roberts 0:6b3ac9c5a042 2589 LoRaMacClassBInitialization();
Wayne Roberts 0:6b3ac9c5a042 2590 Radio::Init( &RadioEvents );
Wayne Roberts 0:6b3ac9c5a042 2591
Wayne Roberts 0:6b3ac9c5a042 2592 // Random seed initialization
Wayne Roberts 0:6b3ac9c5a042 2593 srand(Radio::Random());
Wayne Roberts 0:6b3ac9c5a042 2594
Wayne Roberts 0:6b3ac9c5a042 2595 flags.PublicNetwork = true;
Wayne Roberts 0:6b3ac9c5a042 2596 Radio::SetPublicNetwork( flags.PublicNetwork );
Wayne Roberts 0:6b3ac9c5a042 2597 Radio::Sleep( );
Wayne Roberts 0:6b3ac9c5a042 2598
Wayne Roberts 0:6b3ac9c5a042 2599 McpsIndication.RxSlot = -1;
Wayne Roberts 0:6b3ac9c5a042 2600 function_pending = NULL;
Wayne Roberts 0:6b3ac9c5a042 2601
Wayne Roberts 0:6b3ac9c5a042 2602 McpsConfirm.McpsRequest = MCPS_NONE;
Wayne Roberts 0:6b3ac9c5a042 2603
Wayne Roberts 0:6b3ac9c5a042 2604 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2605 MaxJoinRequestTrials = 1;
Wayne Roberts 0:6b3ac9c5a042 2606 #else
Wayne Roberts 0:6b3ac9c5a042 2607 flags.have_SNwkSIntKey = 0;
Wayne Roberts 0:6b3ac9c5a042 2608 flags.have_NwkSEncKey = 0;
Wayne Roberts 0:6b3ac9c5a042 2609 flags.OptNeg = 0;
Wayne Roberts 0:6b3ac9c5a042 2610 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 2611
Wayne Roberts 0:6b3ac9c5a042 2612 LoRaMacCryptoInit();
Wayne Roberts 0:6b3ac9c5a042 2613
Wayne Roberts 0:6b3ac9c5a042 2614 MlmeIndication.MlmeIndication = MLME_NONE;
Wayne Roberts 0:6b3ac9c5a042 2615
Wayne Roberts 3:eb174e10afbb 2616 ADR_ACK_LIMIT = DEFAULT_ADR_ACK_LIMIT;
Wayne Roberts 3:eb174e10afbb 2617 ADR_ACK_DELAY = DEFAULT_ADR_ACK_DELAY;
Wayne Roberts 3:eb174e10afbb 2618
Wayne Roberts 0:6b3ac9c5a042 2619 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 2620 } // ..LoRaMacInitialization()
Wayne Roberts 0:6b3ac9c5a042 2621
Wayne Roberts 0:6b3ac9c5a042 2622 void SendFrameOnChannel( uint8_t ch_num )
Wayne Roberts 0:6b3ac9c5a042 2623 {
Wayne Roberts 0:6b3ac9c5a042 2624 int8_t txPowerIndex = 0;
Wayne Roberts 0:6b3ac9c5a042 2625 int8_t txPower = 0;
Wayne Roberts 0:6b3ac9c5a042 2626 uint8_t tx_len = tx_buf_len;
Wayne Roberts 0:6b3ac9c5a042 2627 uint32_t mic;
Wayne Roberts 0:6b3ac9c5a042 2628
Wayne Roberts 0:6b3ac9c5a042 2629 /* TODO: if beacon guard, defer until pingslot 0 */
Wayne Roberts 0:6b3ac9c5a042 2630
Wayne Roberts 0:6b3ac9c5a042 2631 last_up_macHdr.Value = Radio::radio.tx_buf[0];
Wayne Roberts 0:6b3ac9c5a042 2632 if (last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_UNCONFIRMED_UP ||
Wayne Roberts 0:6b3ac9c5a042 2633 last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_UP)
Wayne Roberts 0:6b3ac9c5a042 2634 {
Wayne Roberts 3:eb174e10afbb 2635 LoRaMacFrameCtrl_t* fCtrl = (LoRaMacFrameCtrl_t*)&Radio::radio.tx_buf[5];
Wayne Roberts 0:6b3ac9c5a042 2636 block_t block;
Wayne Roberts 0:6b3ac9c5a042 2637 uint32_t fcnt_up;
Wayne Roberts 0:6b3ac9c5a042 2638 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2639 fcnt_up = FCntUp;
Wayne Roberts 0:6b3ac9c5a042 2640 #else
Wayne Roberts 0:6b3ac9c5a042 2641 fcnt_up = eeprom_read(EEPROM_FCNTUP);
Wayne Roberts 0:6b3ac9c5a042 2642 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 3:eb174e10afbb 2643
Wayne Roberts 3:eb174e10afbb 2644 fCtrl->Bits.AdrAckReq = false;
Wayne Roberts 3:eb174e10afbb 2645 if (fCtrl->Bits.Adr) {
Wayne Roberts 3:eb174e10afbb 2646 if (McpsIndication.ADR_ACK_CNT >= ADR_ACK_LIMIT) {
Wayne Roberts 3:eb174e10afbb 2647 if (LoRaMacParamsDefaults.ChannelsDatarate > LORAMAC_TX_MIN_DATARATE || LoRaMacParams.ChannelsTxPower > LORAMAC_DEFAULT_TX_POWER || LoRaMacParams.NbEnabledChannels < LoRaMacParamsDefaults.NbEnabledChannels)
Wayne Roberts 3:eb174e10afbb 2648 fCtrl->Bits.AdrAckReq = true;
Wayne Roberts 3:eb174e10afbb 2649
Wayne Roberts 3:eb174e10afbb 2650 if (McpsIndication.ADR_ACK_CNT >= (ADR_ACK_LIMIT + ADR_ACK_DELAY)) {
Wayne Roberts 3:eb174e10afbb 2651 /* if tx power less than default: increase tx power, otherwise decrease datarate */
Wayne Roberts 3:eb174e10afbb 2652 if (LoRaMacParams.ChannelsTxPower > LORAMAC_DEFAULT_TX_POWER) {
Wayne Roberts 3:eb174e10afbb 2653 LoRaMacParams.ChannelsTxPower--;
Wayne Roberts 3:eb174e10afbb 2654 } else if (LoRaMacParams.ChannelsDatarate > LORAMAC_TX_MIN_DATARATE) {
Wayne Roberts 3:eb174e10afbb 2655 LoRaMacParams.ChannelsDatarate--;
Wayne Roberts 3:eb174e10afbb 2656 McpsIndication.ADR_ACK_CNT -= ADR_ACK_DELAY;
Wayne Roberts 3:eb174e10afbb 2657 } else {
Wayne Roberts 3:eb174e10afbb 2658 memcpy(LoRaMacParams.ChannelsMask, LoRaMacParamsDefaults.ChannelsMask, sizeof(LoRaMacParams.ChannelsMask));
Wayne Roberts 3:eb174e10afbb 2659 LoRaMacParams.NbEnabledChannels = LoRaMacParamsDefaults.NbEnabledChannels;
Wayne Roberts 3:eb174e10afbb 2660 }
Wayne Roberts 3:eb174e10afbb 2661 }
Wayne Roberts 3:eb174e10afbb 2662 }
Wayne Roberts 3:eb174e10afbb 2663 } // ..if (fCtrl->Bits.Adr)
Wayne Roberts 3:eb174e10afbb 2664
Wayne Roberts 0:6b3ac9c5a042 2665 Radio::radio.tx_buf[6] = fcnt_up & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2666 Radio::radio.tx_buf[7] = ( fcnt_up >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2667
Wayne Roberts 0:6b3ac9c5a042 2668 block.b.header = 0x49;
Wayne Roberts 0:6b3ac9c5a042 2669 block.b.confFCnt = 0;
Wayne Roberts 0:6b3ac9c5a042 2670 block.b.dr = 0;
Wayne Roberts 0:6b3ac9c5a042 2671 block.b.ch = 0;
Wayne Roberts 0:6b3ac9c5a042 2672 block.b.dir = UP_LINK;
Wayne Roberts 0:6b3ac9c5a042 2673 block.b.DevAddr = LoRaMacDevAddr;
Wayne Roberts 0:6b3ac9c5a042 2674 block.b.FCnt = fcnt_up;
Wayne Roberts 0:6b3ac9c5a042 2675 block.b.zero8 = 0;
Wayne Roberts 0:6b3ac9c5a042 2676 block.b.lenMsg = tx_len;
Wayne Roberts 0:6b3ac9c5a042 2677 if (flags.OptNeg) {
Wayne Roberts 0:6b3ac9c5a042 2678 uint16_t cmacF, cmacS;
Wayne Roberts 0:6b3ac9c5a042 2679 cmacF = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.FNwkSIntKey);
Wayne Roberts 0:6b3ac9c5a042 2680
Wayne Roberts 0:6b3ac9c5a042 2681 block.b.confFCnt = ConfFCntDown;
Wayne Roberts 0:6b3ac9c5a042 2682 block.b.dr = LoRaMacParams.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 2683 block.b.ch = ch_num;
Wayne Roberts 0:6b3ac9c5a042 2684 cmacS = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.SNwkSIntKey) & 0xffff;
Wayne Roberts 0:6b3ac9c5a042 2685 mic = cmacS | (cmacF << 16);
Wayne Roberts 0:6b3ac9c5a042 2686 ConfFCntDown = 0; /* single use */
Wayne Roberts 0:6b3ac9c5a042 2687 } else
Wayne Roberts 0:6b3ac9c5a042 2688 mic = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.FNwkSIntKey);
Wayne Roberts 0:6b3ac9c5a042 2689
Wayne Roberts 0:6b3ac9c5a042 2690 Radio::radio.tx_buf[tx_buf_len + 0] = mic & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2691 Radio::radio.tx_buf[tx_buf_len + 1] = ( mic >> 8 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2692 Radio::radio.tx_buf[tx_buf_len + 2] = ( mic >> 16 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2693 Radio::radio.tx_buf[tx_buf_len + 3] = ( mic >> 24 ) & 0xFF;
Wayne Roberts 0:6b3ac9c5a042 2694 tx_len += LORAMAC_MFR_LEN;
Wayne Roberts 0:6b3ac9c5a042 2695 MAC_PRINTF("FCntUp%u ", fcnt_up);
Wayne Roberts 0:6b3ac9c5a042 2696
Wayne Roberts 0:6b3ac9c5a042 2697 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2698 McpsConfirm.UpLinkCounter = FCntUp;
Wayne Roberts 0:6b3ac9c5a042 2699 #else
Wayne Roberts 0:6b3ac9c5a042 2700 McpsConfirm.UpLinkCounter = eeprom_read(EEPROM_FCNTUP);
Wayne Roberts 0:6b3ac9c5a042 2701 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 3:eb174e10afbb 2702
Wayne Roberts 3:eb174e10afbb 2703 if (flags.uplink_in_progress <= 1)
Wayne Roberts 3:eb174e10afbb 2704 McpsIndication.ADR_ACK_CNT++;
Wayne Roberts 3:eb174e10afbb 2705
Wayne Roberts 3:eb174e10afbb 2706 } // ..if sending (un)conf
Wayne Roberts 3:eb174e10afbb 2707
Wayne Roberts 3:eb174e10afbb 2708 txPowerIndex = region_LimitTxPower( LoRaMacParams.ChannelsTxPower );
Wayne Roberts 0:6b3ac9c5a042 2709 txPower = TxPowers[txPowerIndex];
Wayne Roberts 0:6b3ac9c5a042 2710
Wayne Roberts 0:6b3ac9c5a042 2711 if (MlmeConfirm.MlmeRequest != MLME_NONE) {
Wayne Roberts 0:6b3ac9c5a042 2712 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_SENDING;
Wayne Roberts 0:6b3ac9c5a042 2713 }
Wayne Roberts 0:6b3ac9c5a042 2714 if (McpsConfirm.McpsRequest != MCPS_NONE) {
Wayne Roberts 0:6b3ac9c5a042 2715 McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_SENDING;
Wayne Roberts 0:6b3ac9c5a042 2716 McpsConfirm.Datarate = LoRaMacParams.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 2717 McpsConfirm.TxPower = txPowerIndex;
Wayne Roberts 0:6b3ac9c5a042 2718 McpsConfirm.UpLinkFreqHz = Channels[ch_num].FreqHz;
Wayne Roberts 0:6b3ac9c5a042 2719 }
Wayne Roberts 0:6b3ac9c5a042 2720
Wayne Roberts 0:6b3ac9c5a042 2721 Radio::SetChannel(Channels[ch_num].FreqHz);
Wayne Roberts 0:6b3ac9c5a042 2722 if (MlmeIndication.MlmeIndication != MLME_NONE)
Wayne Roberts 0:6b3ac9c5a042 2723 MlmeIndication.freqHz = Channels[ch_num].FreqHz;
Wayne Roberts 0:6b3ac9c5a042 2724
Wayne Roberts 0:6b3ac9c5a042 2725 region_tx_setup(txPower, tx_len);
Wayne Roberts 0:6b3ac9c5a042 2726
Wayne Roberts 0:6b3ac9c5a042 2727 // Store the time on air
Wayne Roberts 0:6b3ac9c5a042 2728 //McpsConfirm.TxTimeOnAir = TxTimeOnAir_us;
Wayne Roberts 0:6b3ac9c5a042 2729 //MlmeConfirm.TxTimeOnAir = TxTimeOnAir_us;
Wayne Roberts 0:6b3ac9c5a042 2730
Wayne Roberts 0:6b3ac9c5a042 2731 // Send now
Wayne Roberts 0:6b3ac9c5a042 2732 Radio::Send(tx_len);
Wayne Roberts 0:6b3ac9c5a042 2733 MAC_PRINTF(" sfoc %u, %" PRIu32"hz\r\n", tx_len, Channels[ch_num].FreqHz);
Wayne Roberts 0:6b3ac9c5a042 2734
Wayne Roberts 3:eb174e10afbb 2735 /* if this is unconfirmed up, and last NbTrans */
Wayne Roberts 3:eb174e10afbb 2736 if (last_up_macHdr.Bits.MType == FRAME_TYPE_DATA_UNCONFIRMED_UP && flags.uplink_in_progress <= 1) {
Wayne Roberts 0:6b3ac9c5a042 2737 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 2738 FCntUp++;
Wayne Roberts 0:6b3ac9c5a042 2739 #else
Wayne Roberts 0:6b3ac9c5a042 2740 if (eeprom_increment_value(EEPROM_FCNTUP) < 0) {
Wayne Roberts 0:6b3ac9c5a042 2741 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_INCR_FAIL); // SendFrame fail
Wayne Roberts 0:6b3ac9c5a042 2742 }
Wayne Roberts 0:6b3ac9c5a042 2743 #endif
Wayne Roberts 0:6b3ac9c5a042 2744 }
Wayne Roberts 0:6b3ac9c5a042 2745 } // ..SendFrameOnChannel()
Wayne Roberts 0:6b3ac9c5a042 2746
Wayne Roberts 0:6b3ac9c5a042 2747 uint8_t CountBits( uint16_t mask, uint8_t nbBits )
Wayne Roberts 0:6b3ac9c5a042 2748 {
Wayne Roberts 0:6b3ac9c5a042 2749 uint8_t nbActiveBits = 0;
Wayne Roberts 0:6b3ac9c5a042 2750
Wayne Roberts 0:6b3ac9c5a042 2751 for( uint8_t j = 0; j < nbBits; j++ )
Wayne Roberts 0:6b3ac9c5a042 2752 {
Wayne Roberts 0:6b3ac9c5a042 2753 if( ( mask & ( 1 << j ) ) == ( 1 << j ) )
Wayne Roberts 0:6b3ac9c5a042 2754 {
Wayne Roberts 0:6b3ac9c5a042 2755 nbActiveBits++;
Wayne Roberts 0:6b3ac9c5a042 2756 }
Wayne Roberts 0:6b3ac9c5a042 2757 }
Wayne Roberts 0:6b3ac9c5a042 2758 return nbActiveBits;
Wayne Roberts 0:6b3ac9c5a042 2759 }
Wayne Roberts 0:6b3ac9c5a042 2760
Wayne Roberts 0:6b3ac9c5a042 2761 void LoRaMacPrintStatus()
Wayne Roberts 0:6b3ac9c5a042 2762 {
Wayne Roberts 0:6b3ac9c5a042 2763 MAC_PRINTF("uplink_in_progress:%u, ConfFCntUp%u\r\n", flags.uplink_in_progress, ConfFCntUp);
Wayne Roberts 0:6b3ac9c5a042 2764 MAC_PRINTF("function_pending:%p\r\n", function_pending);
Wayne Roberts 0:6b3ac9c5a042 2765 MAC_PRINTF("rx delays:%u, %u, %u, %u\r\n",
Wayne Roberts 0:6b3ac9c5a042 2766 RxWindow1Delay_us,
Wayne Roberts 0:6b3ac9c5a042 2767 LoRaMacParams.ReceiveDelay1_us,
Wayne Roberts 0:6b3ac9c5a042 2768 RxWindow2Delay_us,
Wayne Roberts 0:6b3ac9c5a042 2769 LoRaMacParams.ReceiveDelay2_us
Wayne Roberts 0:6b3ac9c5a042 2770 );
Wayne Roberts 0:6b3ac9c5a042 2771 if (flags.uplink_in_progress) {
Wayne Roberts 0:6b3ac9c5a042 2772 MAC_PRINTF("since txDone:%u\r\n", Radio::lpt.read_us() - tx_done_at);
Wayne Roberts 0:6b3ac9c5a042 2773 }
Wayne Roberts 0:6b3ac9c5a042 2774
Wayne Roberts 0:6b3ac9c5a042 2775 Radio::PrintStatus();
Wayne Roberts 0:6b3ac9c5a042 2776 }
Wayne Roberts 0:6b3ac9c5a042 2777
Wayne Roberts 0:6b3ac9c5a042 2778 us_timestamp_t LoRaMacReadTimer()
Wayne Roberts 0:6b3ac9c5a042 2779 {
Wayne Roberts 0:6b3ac9c5a042 2780 return Radio::lpt.read_us();
Wayne Roberts 0:6b3ac9c5a042 2781 }
Wayne Roberts 0:6b3ac9c5a042 2782
Wayne Roberts 0:6b3ac9c5a042 2783 int8_t
Wayne Roberts 0:6b3ac9c5a042 2784 LoRaMacGetRxSlot()
Wayne Roberts 0:6b3ac9c5a042 2785 {
Wayne Roberts 0:6b3ac9c5a042 2786 return McpsIndication.RxSlot;
Wayne Roberts 0:6b3ac9c5a042 2787 }
Wayne Roberts 4:e4bfe9183f94 2788
Wayne Roberts 4:e4bfe9183f94 2789 void
Wayne Roberts 4:e4bfe9183f94 2790 LoRaMacUserContext()
Wayne Roberts 4:e4bfe9183f94 2791 {
Wayne Roberts 4:e4bfe9183f94 2792 Radio::UserContext();
Wayne Roberts 4:e4bfe9183f94 2793
Wayne Roberts 4:e4bfe9183f94 2794 if (flags.OnTxDelayed) {
Wayne Roberts 4:e4bfe9183f94 2795 OnTxDelayedTimerEvent();
Wayne Roberts 4:e4bfe9183f94 2796 flags.OnTxDelayed = false;
Wayne Roberts 4:e4bfe9183f94 2797 }
Wayne Roberts 4:e4bfe9183f94 2798 }
Wayne Roberts 4:e4bfe9183f94 2799