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 Jun 11 14:09:16 2018 -0700
Revision:
9:fe8e08792ae9
Parent:
0:6b3ac9c5a042
sx126x: update xfer() calls

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:6b3ac9c5a042 1 #include <stdint.h>
Wayne Roberts 0:6b3ac9c5a042 2 #include <stdbool.h>
Wayne Roberts 0:6b3ac9c5a042 3 #include "eeprom.h"
Wayne Roberts 0:6b3ac9c5a042 4 #include "Commissioning.h"
Wayne Roberts 0:6b3ac9c5a042 5
Wayne Roberts 0:6b3ac9c5a042 6 #include <stm32l1xx.h>
Wayne Roberts 0:6b3ac9c5a042 7 #define DEVNONCE_BASE FLASH_EEPROM_BASE
Wayne Roberts 0:6b3ac9c5a042 8
Wayne Roberts 0:6b3ac9c5a042 9 #define DEVNONCE_END (DEVNONCE_BASE + 16) /* eight uint16_t values */
Wayne Roberts 0:6b3ac9c5a042 10 #define RJCOUNT1_BASE DEVNONCE_END
Wayne Roberts 0:6b3ac9c5a042 11 #define RJCOUNT1_END (RJCOUNT1_BASE + 16)
Wayne Roberts 0:6b3ac9c5a042 12 #define FCNTUP_BASE RJCOUNT1_END
Wayne Roberts 0:6b3ac9c5a042 13 #define FCNTUP_END (FCNTUP_BASE + 32) /* eight uint32_t values */
Wayne Roberts 0:6b3ac9c5a042 14 #define NFCNTDWN_BASE FCNTUP_END
Wayne Roberts 0:6b3ac9c5a042 15 #define NFCNTDWN_END (NFCNTDWN_BASE + 32) /* eight uint32_t values */
Wayne Roberts 0:6b3ac9c5a042 16 #define AFCNTDWN_BASE NFCNTDWN_END
Wayne Roberts 0:6b3ac9c5a042 17 #define AFCNTDWN_END (AFCNTDWN_BASE + 32) /* eight uint32_t values */
Wayne Roberts 0:6b3ac9c5a042 18
Wayne Roberts 0:6b3ac9c5a042 19 #if defined(LORAWAN_JOIN_EUI) && defined(LORAWAN_ROOT_APPKEY)
Wayne Roberts 0:6b3ac9c5a042 20 #define JOINNONCE_BASE AFCNTDWN_END
Wayne Roberts 0:6b3ac9c5a042 21 #define JOINNONCE_END (JOINNONCE_BASE + 32)
Wayne Roberts 0:6b3ac9c5a042 22 #endif // 1v1 OTA
Wayne Roberts 0:6b3ac9c5a042 23
Wayne Roberts 0:6b3ac9c5a042 24 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 25 static uint16_t eeprom_read_halfword(uint32_t baseAddr, uint32_t endAddr)
Wayne Roberts 0:6b3ac9c5a042 26 {
Wayne Roberts 0:6b3ac9c5a042 27 uint16_t* u16_ptr = (uint16_t*)baseAddr;
Wayne Roberts 0:6b3ac9c5a042 28 uint16_t max_val = 0;
Wayne Roberts 0:6b3ac9c5a042 29 while (u16_ptr < (uint16_t*)endAddr) {
Wayne Roberts 0:6b3ac9c5a042 30 if (*u16_ptr > max_val)
Wayne Roberts 0:6b3ac9c5a042 31 max_val = *u16_ptr;
Wayne Roberts 0:6b3ac9c5a042 32
Wayne Roberts 0:6b3ac9c5a042 33 u16_ptr++;
Wayne Roberts 0:6b3ac9c5a042 34 }
Wayne Roberts 0:6b3ac9c5a042 35 return max_val;
Wayne Roberts 0:6b3ac9c5a042 36 }
Wayne Roberts 0:6b3ac9c5a042 37 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 38
Wayne Roberts 0:6b3ac9c5a042 39 #ifndef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 40 static uint32_t eeprom_read_word(uint32_t baseAddr, uint32_t endAddr)
Wayne Roberts 0:6b3ac9c5a042 41 {
Wayne Roberts 0:6b3ac9c5a042 42 uint32_t* u32_ptr = (uint32_t*)baseAddr;
Wayne Roberts 0:6b3ac9c5a042 43 uint32_t max_val = 0;
Wayne Roberts 0:6b3ac9c5a042 44 while (u32_ptr < (uint32_t*)endAddr) {
Wayne Roberts 0:6b3ac9c5a042 45 if (*u32_ptr > max_val)
Wayne Roberts 0:6b3ac9c5a042 46 max_val = *u32_ptr;
Wayne Roberts 0:6b3ac9c5a042 47
Wayne Roberts 0:6b3ac9c5a042 48 u32_ptr++;
Wayne Roberts 0:6b3ac9c5a042 49 }
Wayne Roberts 0:6b3ac9c5a042 50 return max_val;
Wayne Roberts 0:6b3ac9c5a042 51 }
Wayne Roberts 0:6b3ac9c5a042 52 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 53
Wayne Roberts 0:6b3ac9c5a042 54 uint32_t eeprom_read(eeprom_value_e ev)
Wayne Roberts 0:6b3ac9c5a042 55 {
Wayne Roberts 0:6b3ac9c5a042 56 switch (ev) {
Wayne Roberts 0:6b3ac9c5a042 57 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 58 case EEPROM_DEVNONCE:
Wayne Roberts 0:6b3ac9c5a042 59 return eeprom_read_halfword(DEVNONCE_BASE, DEVNONCE_END);
Wayne Roberts 0:6b3ac9c5a042 60 case EEPROM_RJCOUNT1:
Wayne Roberts 0:6b3ac9c5a042 61 return eeprom_read_halfword(RJCOUNT1_BASE, RJCOUNT1_END);
Wayne Roberts 0:6b3ac9c5a042 62 #ifdef LORAWAN_ROOT_APPKEY
Wayne Roberts 0:6b3ac9c5a042 63 case EEPROM_JOINNONCE:
Wayne Roberts 0:6b3ac9c5a042 64 return eeprom_read_halfword(JOINNONCE_BASE, JOINNONCE_END);
Wayne Roberts 0:6b3ac9c5a042 65 #endif /* LORAWAN_ROOT_APPKEY */
Wayne Roberts 0:6b3ac9c5a042 66 #else
Wayne Roberts 0:6b3ac9c5a042 67 case EEPROM_FCNTUP:
Wayne Roberts 0:6b3ac9c5a042 68 return eeprom_read_word(FCNTUP_BASE, FCNTUP_END);
Wayne Roberts 0:6b3ac9c5a042 69 case EEPROM_NFCNTDWN:
Wayne Roberts 0:6b3ac9c5a042 70 return eeprom_read_word(NFCNTDWN_BASE, NFCNTDWN_END);
Wayne Roberts 0:6b3ac9c5a042 71 case EEPROM_AFCNTDWN:
Wayne Roberts 0:6b3ac9c5a042 72 return eeprom_read_word(AFCNTDWN_BASE, AFCNTDWN_END);
Wayne Roberts 0:6b3ac9c5a042 73 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 74 default: return 0;
Wayne Roberts 0:6b3ac9c5a042 75 }
Wayne Roberts 0:6b3ac9c5a042 76 }
Wayne Roberts 0:6b3ac9c5a042 77
Wayne Roberts 0:6b3ac9c5a042 78 static void _getmax_halfword(uint32_t baseAddr, uint32_t endAddr, uint32_t* _max_val_at, uint32_t* max_val)
Wayne Roberts 0:6b3ac9c5a042 79 {
Wayne Roberts 0:6b3ac9c5a042 80 uint16_t* u16_ptr = (uint16_t*)baseAddr;
Wayne Roberts 0:6b3ac9c5a042 81 uint16_t* max_val_at = NULL;
Wayne Roberts 0:6b3ac9c5a042 82
Wayne Roberts 0:6b3ac9c5a042 83 while (u16_ptr < (uint16_t*)endAddr) {
Wayne Roberts 0:6b3ac9c5a042 84 if (*u16_ptr > *max_val) {
Wayne Roberts 0:6b3ac9c5a042 85 *max_val = *u16_ptr;
Wayne Roberts 0:6b3ac9c5a042 86 max_val_at = u16_ptr;
Wayne Roberts 0:6b3ac9c5a042 87 }
Wayne Roberts 0:6b3ac9c5a042 88
Wayne Roberts 0:6b3ac9c5a042 89 u16_ptr++;
Wayne Roberts 0:6b3ac9c5a042 90 }
Wayne Roberts 0:6b3ac9c5a042 91
Wayne Roberts 0:6b3ac9c5a042 92 if (max_val_at == NULL) {
Wayne Roberts 0:6b3ac9c5a042 93 /* first time */
Wayne Roberts 0:6b3ac9c5a042 94 max_val_at = (uint16_t*)baseAddr;
Wayne Roberts 0:6b3ac9c5a042 95 } else {
Wayne Roberts 0:6b3ac9c5a042 96 if (++max_val_at == (uint16_t*)endAddr)
Wayne Roberts 0:6b3ac9c5a042 97 max_val_at = (uint16_t*)baseAddr;
Wayne Roberts 0:6b3ac9c5a042 98 }
Wayne Roberts 0:6b3ac9c5a042 99
Wayne Roberts 0:6b3ac9c5a042 100 *_max_val_at = (uint32_t)max_val_at;
Wayne Roberts 0:6b3ac9c5a042 101 }
Wayne Roberts 0:6b3ac9c5a042 102
Wayne Roberts 0:6b3ac9c5a042 103 static void _getmax_word(uint32_t baseAddr, uint32_t endAddr, uint32_t* max_val_at, uint32_t* max_val)
Wayne Roberts 0:6b3ac9c5a042 104 {
Wayne Roberts 0:6b3ac9c5a042 105 uint32_t* u32_ptr = (uint32_t*)baseAddr;
Wayne Roberts 0:6b3ac9c5a042 106
Wayne Roberts 0:6b3ac9c5a042 107 while (u32_ptr < (uint32_t*)endAddr) {
Wayne Roberts 0:6b3ac9c5a042 108 if (*u32_ptr > *max_val) {
Wayne Roberts 0:6b3ac9c5a042 109 *max_val = *u32_ptr;
Wayne Roberts 0:6b3ac9c5a042 110 *max_val_at = (uint32_t)u32_ptr;
Wayne Roberts 0:6b3ac9c5a042 111 }
Wayne Roberts 0:6b3ac9c5a042 112
Wayne Roberts 0:6b3ac9c5a042 113 u32_ptr++;
Wayne Roberts 0:6b3ac9c5a042 114 }
Wayne Roberts 0:6b3ac9c5a042 115
Wayne Roberts 0:6b3ac9c5a042 116 if (*max_val_at == 0) {
Wayne Roberts 0:6b3ac9c5a042 117 /* first time */
Wayne Roberts 0:6b3ac9c5a042 118 *max_val_at = baseAddr;
Wayne Roberts 0:6b3ac9c5a042 119 } else {
Wayne Roberts 0:6b3ac9c5a042 120 *max_val_at += sizeof(uint32_t);
Wayne Roberts 0:6b3ac9c5a042 121 if (*max_val_at == endAddr)
Wayne Roberts 0:6b3ac9c5a042 122 *max_val_at = baseAddr;
Wayne Roberts 0:6b3ac9c5a042 123 }
Wayne Roberts 0:6b3ac9c5a042 124 }
Wayne Roberts 0:6b3ac9c5a042 125
Wayne Roberts 0:6b3ac9c5a042 126 static int increment_eeprom(uint32_t erase_type, uint32_t baseAddr, uint32_t endAddr)
Wayne Roberts 0:6b3ac9c5a042 127 {
Wayne Roberts 0:6b3ac9c5a042 128 bool erased;
Wayne Roberts 0:6b3ac9c5a042 129 HAL_StatusTypeDef status;
Wayne Roberts 0:6b3ac9c5a042 130 uint32_t prog_type;
Wayne Roberts 0:6b3ac9c5a042 131 uint32_t max_val_at = 0;
Wayne Roberts 0:6b3ac9c5a042 132 uint32_t max_val = 0;
Wayne Roberts 0:6b3ac9c5a042 133
Wayne Roberts 0:6b3ac9c5a042 134 if (erase_type == FLASH_TYPEERASEDATA_HALFWORD) {
Wayne Roberts 0:6b3ac9c5a042 135 _getmax_halfword(baseAddr, endAddr, &max_val_at, &max_val);
Wayne Roberts 0:6b3ac9c5a042 136 prog_type = FLASH_TYPEPROGRAMDATA_HALFWORD;
Wayne Roberts 0:6b3ac9c5a042 137 } else if (erase_type == FLASH_TYPEERASEDATA_WORD) {
Wayne Roberts 0:6b3ac9c5a042 138 _getmax_word(baseAddr, endAddr, &max_val_at, &max_val);
Wayne Roberts 0:6b3ac9c5a042 139 prog_type = FLASH_TYPEPROGRAMDATA_WORD;
Wayne Roberts 0:6b3ac9c5a042 140 } else
Wayne Roberts 0:6b3ac9c5a042 141 return -1;
Wayne Roberts 0:6b3ac9c5a042 142 /* max_val_at now points to oldest */
Wayne Roberts 0:6b3ac9c5a042 143
Wayne Roberts 0:6b3ac9c5a042 144 // 32bit FLASH_TYPEERASEDATA_WORD
Wayne Roberts 0:6b3ac9c5a042 145 // 16bit FLASH_TYPEERASEDATA_HALFWORD
Wayne Roberts 0:6b3ac9c5a042 146 // 8bit FLASH_TYPEERASEDATA_BYTE
Wayne Roberts 0:6b3ac9c5a042 147 do {
Wayne Roberts 0:6b3ac9c5a042 148 status = HAL_FLASHEx_DATAEEPROM_Erase(erase_type, max_val_at);
Wayne Roberts 0:6b3ac9c5a042 149 if (status == HAL_OK)
Wayne Roberts 0:6b3ac9c5a042 150 erased = true;
Wayne Roberts 0:6b3ac9c5a042 151 else if (status == HAL_ERROR && HAL_FLASH_GetError() == HAL_FLASH_ERROR_WRP) {
Wayne Roberts 0:6b3ac9c5a042 152 if (HAL_FLASHEx_DATAEEPROM_Unlock() != HAL_OK)
Wayne Roberts 0:6b3ac9c5a042 153 return -2;
Wayne Roberts 0:6b3ac9c5a042 154 } else
Wayne Roberts 0:6b3ac9c5a042 155 return -3;
Wayne Roberts 0:6b3ac9c5a042 156 } while (!erased);
Wayne Roberts 0:6b3ac9c5a042 157
Wayne Roberts 0:6b3ac9c5a042 158 if (HAL_FLASHEx_DATAEEPROM_Program(prog_type, max_val_at, max_val + 1) != HAL_OK) {
Wayne Roberts 0:6b3ac9c5a042 159 HAL_FLASHEx_DATAEEPROM_Lock();
Wayne Roberts 0:6b3ac9c5a042 160 return -4;
Wayne Roberts 0:6b3ac9c5a042 161 }
Wayne Roberts 0:6b3ac9c5a042 162
Wayne Roberts 0:6b3ac9c5a042 163 if (HAL_FLASHEx_DATAEEPROM_Lock() != HAL_OK)
Wayne Roberts 0:6b3ac9c5a042 164 return -5;
Wayne Roberts 0:6b3ac9c5a042 165
Wayne Roberts 0:6b3ac9c5a042 166 return 0;
Wayne Roberts 0:6b3ac9c5a042 167 }
Wayne Roberts 0:6b3ac9c5a042 168
Wayne Roberts 0:6b3ac9c5a042 169 int eeprom_increment_value(eeprom_value_e ev)
Wayne Roberts 0:6b3ac9c5a042 170 {
Wayne Roberts 0:6b3ac9c5a042 171 switch (ev) {
Wayne Roberts 0:6b3ac9c5a042 172 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 173 case EEPROM_DEVNONCE:
Wayne Roberts 0:6b3ac9c5a042 174 return increment_eeprom(FLASH_TYPEERASEDATA_HALFWORD, DEVNONCE_BASE, DEVNONCE_END);
Wayne Roberts 0:6b3ac9c5a042 175 case EEPROM_RJCOUNT1:
Wayne Roberts 0:6b3ac9c5a042 176 return increment_eeprom(FLASH_TYPEERASEDATA_HALFWORD, RJCOUNT1_BASE, RJCOUNT1_END);
Wayne Roberts 0:6b3ac9c5a042 177 #ifdef LORAWAN_ROOT_APPKEY
Wayne Roberts 0:6b3ac9c5a042 178 case EEPROM_JOINNONCE:
Wayne Roberts 0:6b3ac9c5a042 179 return increment_eeprom(FLASH_TYPEERASEDATA_WORD, JOINNONCE_BASE, JOINNONCE_END);
Wayne Roberts 0:6b3ac9c5a042 180 #endif /* LORAWAN_ROOT_APPKEY */
Wayne Roberts 0:6b3ac9c5a042 181 #else
Wayne Roberts 0:6b3ac9c5a042 182 case EEPROM_FCNTUP:
Wayne Roberts 0:6b3ac9c5a042 183 return increment_eeprom(FLASH_TYPEERASEDATA_WORD, FCNTUP_BASE, FCNTUP_END);
Wayne Roberts 0:6b3ac9c5a042 184 case EEPROM_NFCNTDWN:
Wayne Roberts 0:6b3ac9c5a042 185 return increment_eeprom(FLASH_TYPEERASEDATA_WORD, NFCNTDWN_BASE, NFCNTDWN_END);
Wayne Roberts 0:6b3ac9c5a042 186 case EEPROM_AFCNTDWN:
Wayne Roberts 0:6b3ac9c5a042 187 return increment_eeprom(FLASH_TYPEERASEDATA_WORD, AFCNTDWN_BASE, AFCNTDWN_END);
Wayne Roberts 0:6b3ac9c5a042 188 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 189 default:
Wayne Roberts 0:6b3ac9c5a042 190 return -1;
Wayne Roberts 0:6b3ac9c5a042 191 }
Wayne Roberts 0:6b3ac9c5a042 192 }
Wayne Roberts 0:6b3ac9c5a042 193
Wayne Roberts 0:6b3ac9c5a042 194 static int _eeprom_clear(uint32_t type, uint32_t baseAddr, uint32_t endAddr)
Wayne Roberts 0:6b3ac9c5a042 195 {
Wayne Roberts 0:6b3ac9c5a042 196 int ret = 0;
Wayne Roberts 0:6b3ac9c5a042 197 HAL_StatusTypeDef status;
Wayne Roberts 0:6b3ac9c5a042 198
Wayne Roberts 0:6b3ac9c5a042 199 if (HAL_FLASHEx_DATAEEPROM_Unlock() != HAL_OK) {
Wayne Roberts 0:6b3ac9c5a042 200 HAL_FLASHEx_DATAEEPROM_Lock();
Wayne Roberts 0:6b3ac9c5a042 201 return -1;
Wayne Roberts 0:6b3ac9c5a042 202 }
Wayne Roberts 0:6b3ac9c5a042 203
Wayne Roberts 0:6b3ac9c5a042 204 if (type == FLASH_TYPEERASEDATA_HALFWORD) {
Wayne Roberts 0:6b3ac9c5a042 205 uint16_t* u16_ptr = (uint16_t*)baseAddr;
Wayne Roberts 0:6b3ac9c5a042 206 while (u16_ptr < (uint16_t*)endAddr) {
Wayne Roberts 0:6b3ac9c5a042 207 if (*u16_ptr != 0) {
Wayne Roberts 0:6b3ac9c5a042 208 status = HAL_FLASHEx_DATAEEPROM_Erase(type, (uint32_t)u16_ptr);
Wayne Roberts 0:6b3ac9c5a042 209 if (status != HAL_OK) {
Wayne Roberts 0:6b3ac9c5a042 210 ret = -2;
Wayne Roberts 0:6b3ac9c5a042 211 break;
Wayne Roberts 0:6b3ac9c5a042 212 }
Wayne Roberts 0:6b3ac9c5a042 213 }
Wayne Roberts 0:6b3ac9c5a042 214 u16_ptr++;
Wayne Roberts 0:6b3ac9c5a042 215 }
Wayne Roberts 0:6b3ac9c5a042 216 } else if (type == FLASH_TYPEERASEDATA_WORD) {
Wayne Roberts 0:6b3ac9c5a042 217 uint32_t* u32_ptr = (uint32_t*)baseAddr;
Wayne Roberts 0:6b3ac9c5a042 218 while (u32_ptr < (uint32_t*)endAddr) {
Wayne Roberts 0:6b3ac9c5a042 219 if (*u32_ptr != 0) {
Wayne Roberts 0:6b3ac9c5a042 220 status = HAL_FLASHEx_DATAEEPROM_Erase(type, (uint32_t)u32_ptr);
Wayne Roberts 0:6b3ac9c5a042 221 if (status != HAL_OK) {
Wayne Roberts 0:6b3ac9c5a042 222 ret = -3;
Wayne Roberts 0:6b3ac9c5a042 223 }
Wayne Roberts 0:6b3ac9c5a042 224 }
Wayne Roberts 0:6b3ac9c5a042 225 u32_ptr++;
Wayne Roberts 0:6b3ac9c5a042 226 }
Wayne Roberts 0:6b3ac9c5a042 227 } else
Wayne Roberts 0:6b3ac9c5a042 228 ret = -1;
Wayne Roberts 0:6b3ac9c5a042 229
Wayne Roberts 0:6b3ac9c5a042 230 HAL_FLASHEx_DATAEEPROM_Lock();
Wayne Roberts 0:6b3ac9c5a042 231
Wayne Roberts 0:6b3ac9c5a042 232 return ret;
Wayne Roberts 0:6b3ac9c5a042 233 }
Wayne Roberts 0:6b3ac9c5a042 234
Wayne Roberts 0:6b3ac9c5a042 235 int eeprom_clear(eeprom_value_e ev)
Wayne Roberts 0:6b3ac9c5a042 236 {
Wayne Roberts 0:6b3ac9c5a042 237 switch (ev) {
Wayne Roberts 0:6b3ac9c5a042 238 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 239 case EEPROM_DEVNONCE:
Wayne Roberts 0:6b3ac9c5a042 240 return _eeprom_clear(FLASH_TYPEERASEDATA_HALFWORD, DEVNONCE_BASE, DEVNONCE_END);
Wayne Roberts 0:6b3ac9c5a042 241 case EEPROM_RJCOUNT1:
Wayne Roberts 0:6b3ac9c5a042 242 return _eeprom_clear(FLASH_TYPEERASEDATA_HALFWORD, RJCOUNT1_BASE, RJCOUNT1_END);
Wayne Roberts 0:6b3ac9c5a042 243 #ifdef LORAWAN_ROOT_APPKEY
Wayne Roberts 0:6b3ac9c5a042 244 case EEPROM_JOINNONCE:
Wayne Roberts 0:6b3ac9c5a042 245 return _eeprom_clear(FLASH_TYPEERASEDATA_WORD, JOINNONCE_BASE, JOINNONCE_END);
Wayne Roberts 0:6b3ac9c5a042 246 #endif /* LORAWAN_ROOT_APPKEY */
Wayne Roberts 0:6b3ac9c5a042 247 #else
Wayne Roberts 0:6b3ac9c5a042 248 case EEPROM_FCNTUP:
Wayne Roberts 0:6b3ac9c5a042 249 return _eeprom_clear(FLASH_TYPEERASEDATA_WORD, FCNTUP_BASE, FCNTUP_END);
Wayne Roberts 0:6b3ac9c5a042 250 case EEPROM_NFCNTDWN:
Wayne Roberts 0:6b3ac9c5a042 251 return _eeprom_clear(FLASH_TYPEERASEDATA_WORD, NFCNTDWN_BASE, NFCNTDWN_END);
Wayne Roberts 0:6b3ac9c5a042 252 case EEPROM_AFCNTDWN:
Wayne Roberts 0:6b3ac9c5a042 253 return _eeprom_clear(FLASH_TYPEERASEDATA_WORD, AFCNTDWN_BASE, AFCNTDWN_END);
Wayne Roberts 0:6b3ac9c5a042 254 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 255 default: return 0;
Wayne Roberts 0:6b3ac9c5a042 256 }
Wayne Roberts 0:6b3ac9c5a042 257 }
Wayne Roberts 0:6b3ac9c5a042 258
Wayne Roberts 0:6b3ac9c5a042 259 #if !defined(LORAWAN_JOIN_EUI) || (defined(LORAWAN_JOIN_EUI) && defined(LORAWAN_ROOT_APPKEY))
Wayne Roberts 0:6b3ac9c5a042 260 static int _write_word(uint32_t baseAddr, uint32_t endAddr, uint32_t value)
Wayne Roberts 0:6b3ac9c5a042 261 {
Wayne Roberts 0:6b3ac9c5a042 262 bool erased;
Wayne Roberts 0:6b3ac9c5a042 263 HAL_StatusTypeDef status;
Wayne Roberts 0:6b3ac9c5a042 264 uint32_t max_val_at = 0;
Wayne Roberts 0:6b3ac9c5a042 265 uint32_t max_val = 0;
Wayne Roberts 0:6b3ac9c5a042 266
Wayne Roberts 0:6b3ac9c5a042 267 _getmax_word(baseAddr, endAddr, &max_val_at, &max_val);
Wayne Roberts 0:6b3ac9c5a042 268
Wayne Roberts 0:6b3ac9c5a042 269 do {
Wayne Roberts 0:6b3ac9c5a042 270 status = HAL_FLASHEx_DATAEEPROM_Erase(FLASH_TYPEERASEDATA_WORD, max_val_at);
Wayne Roberts 0:6b3ac9c5a042 271 if (status == HAL_OK)
Wayne Roberts 0:6b3ac9c5a042 272 erased = true;
Wayne Roberts 0:6b3ac9c5a042 273 else if (status == HAL_ERROR && HAL_FLASH_GetError() == HAL_FLASH_ERROR_WRP) {
Wayne Roberts 0:6b3ac9c5a042 274 if (HAL_FLASHEx_DATAEEPROM_Unlock() != HAL_OK)
Wayne Roberts 0:6b3ac9c5a042 275 return -2;
Wayne Roberts 0:6b3ac9c5a042 276 } else
Wayne Roberts 0:6b3ac9c5a042 277 return -3;
Wayne Roberts 0:6b3ac9c5a042 278 } while (!erased);
Wayne Roberts 0:6b3ac9c5a042 279
Wayne Roberts 0:6b3ac9c5a042 280 if (HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, max_val_at, value) != HAL_OK) {
Wayne Roberts 0:6b3ac9c5a042 281 HAL_FLASHEx_DATAEEPROM_Lock();
Wayne Roberts 0:6b3ac9c5a042 282 return -4;
Wayne Roberts 0:6b3ac9c5a042 283 }
Wayne Roberts 0:6b3ac9c5a042 284
Wayne Roberts 0:6b3ac9c5a042 285 if (HAL_FLASHEx_DATAEEPROM_Lock() != HAL_OK)
Wayne Roberts 0:6b3ac9c5a042 286 return -5;
Wayne Roberts 0:6b3ac9c5a042 287
Wayne Roberts 0:6b3ac9c5a042 288 return 0;
Wayne Roberts 0:6b3ac9c5a042 289 }
Wayne Roberts 0:6b3ac9c5a042 290 #endif
Wayne Roberts 0:6b3ac9c5a042 291
Wayne Roberts 0:6b3ac9c5a042 292 int eeprom_write_word(eeprom_value_e ev, uint32_t value)
Wayne Roberts 0:6b3ac9c5a042 293 {
Wayne Roberts 0:6b3ac9c5a042 294 switch (ev) {
Wayne Roberts 0:6b3ac9c5a042 295 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 0:6b3ac9c5a042 296 case EEPROM_DEVNONCE:
Wayne Roberts 0:6b3ac9c5a042 297 case EEPROM_RJCOUNT1:
Wayne Roberts 0:6b3ac9c5a042 298 return -1;
Wayne Roberts 0:6b3ac9c5a042 299 #ifdef LORAWAN_ROOT_APPKEY
Wayne Roberts 0:6b3ac9c5a042 300 case EEPROM_JOINNONCE:
Wayne Roberts 0:6b3ac9c5a042 301 return _write_word(JOINNONCE_BASE, JOINNONCE_END, value);
Wayne Roberts 0:6b3ac9c5a042 302 #endif /* LORAWAN_ROOT_APPKEY */
Wayne Roberts 0:6b3ac9c5a042 303 #else
Wayne Roberts 0:6b3ac9c5a042 304 case EEPROM_FCNTUP:
Wayne Roberts 0:6b3ac9c5a042 305 return _write_word(FCNTUP_BASE, FCNTUP_END, value);
Wayne Roberts 0:6b3ac9c5a042 306 case EEPROM_NFCNTDWN:
Wayne Roberts 0:6b3ac9c5a042 307 return _write_word(NFCNTDWN_BASE, NFCNTDWN_END, value);
Wayne Roberts 0:6b3ac9c5a042 308 case EEPROM_AFCNTDWN:
Wayne Roberts 0:6b3ac9c5a042 309 return _write_word(AFCNTDWN_BASE, AFCNTDWN_END, value);
Wayne Roberts 0:6b3ac9c5a042 310 #endif /* !LORAWAN_JOIN_EUI */
Wayne Roberts 0:6b3ac9c5a042 311 default:
Wayne Roberts 0:6b3ac9c5a042 312 return -1;
Wayne Roberts 0:6b3ac9c5a042 313 }
Wayne Roberts 0:6b3ac9c5a042 314 }
Wayne Roberts 0:6b3ac9c5a042 315