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 Aug 20 14:09:49 2018 -0700
Revision:
12:0f28f2e7c35e
Parent:
10:9a7a8b8d0ac2
add 8 hybrid channel sets for us915 band

Who changed what in which revision?

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