Select one of the symbols to view example projects that use it.
 
Outline
#include "WL_Ext_Safe.h"
#include <stdlib.h>
#include <inttypes.h>
#include "esp_log.h"
TAG
#define FLASH_ERASE_VALUE
#define WL_EXT_SAFE_OK
WL_Ext_Safe_State
WL_Ext_Safe::WL_Ext_Safe()
WL_Ext_Safe::~WL_Ext_Safe()
WL_Ext_Safe::config(WL_Config_s *, Partition *)
WL_Ext_Safe::init()
WL_Ext_Safe::get_flash_size()
WL_Ext_Safe::recover()
WL_Ext_Safe::erase_sector_fit(uint32_t, uint32_t)
Files
loading...
SourceVuESP-IDF Framework and ExamplesESP-IDFcomponents/wear_levelling/WL_Ext_Safe.cpp
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 *//* ... */ #include "WL_Ext_Safe.h" #include <stdlib.h> #include <inttypes.h> #include "esp_log.h" static const char *TAG = "wl_ext_safe"; #define WL_EXT_RESULT_CHECK(result) \ if (result != ESP_OK) { \ ESP_LOGE(TAG,"%s(%d): result = 0x%08" PRIx32, __FUNCTION__, __LINE__, (uint32_t) result); \ return (result); \ }{...} ... #ifndef FLASH_ERASE_VALUE #define FLASH_ERASE_VALUE 0xffffffff #endif // FLASH_ERASE_VALUE #ifndef WL_EXT_SAFE_OK #define WL_EXT_SAFE_OK 0x12345678 #endif // WL_EXT_SAFE_OK /* WL_Ext_Safe_State stores the buffer transaction state in between erase and write operation of the sector. This is mainly for safety purpose, in case of power outage in between erase and write operation, data will be recovered after power outage as temporary data is also stored on flash memory (dump_addr). - sector_restore_sign : if any transaction was pending before power outage, then on power up, this should be WL_EXT_SAFE_OK which indicates that data recovery from dump buffer is needed, else it should be zero. - sector_base_addr : sector base address where data from dump buffer will be restored. - sector_base_addr_offset : sector base address offset at which data will be restored *//* ... */ struct WL_Ext_Safe_State { public: uint32_t sector_restore_sign; uint32_t sector_base_addr; uint32_t sector_base_addr_offset; uint32_t count;... }{ ... }; WL_Ext_Safe::WL_Ext_Safe(): WL_Ext_Perf() { }{ ... } WL_Ext_Safe::~WL_Ext_Safe() { }{ ... } esp_err_t WL_Ext_Safe::config(WL_Config_s *cfg, Partition *partition) { esp_err_t result = ESP_OK; result = WL_Ext_Perf::config(cfg, partition); WL_EXT_RESULT_CHECK(result); /* two extra sectors will be reserved to store buffer transaction state WL_Ext_Safe_State and temporary storage of the actual sector data from the sector which is to be erased*//* ... */ this->buff_trans_state_addr = WL_Ext_Perf::get_flash_size() - 2 * this->flash_sector_size; this->dump_addr = WL_Ext_Perf::get_flash_size() - 1 * this->flash_sector_size; return ESP_OK; }{ ... } esp_err_t WL_Ext_Safe::init() { esp_err_t result = ESP_OK; ESP_LOGV(TAG, "%s", __func__); result = WL_Ext_Perf::init(); WL_EXT_RESULT_CHECK(result); //check if any buffer write operation was pending and recover data if needed result = this->recover(); return result; }{ ... } size_t WL_Ext_Safe::get_flash_size() { ESP_LOGV(TAG, "%s size = %" PRIu32, __func__, (uint32_t) (WL_Ext_Perf::get_flash_size() - 2 * this->flash_sector_size)); return WL_Ext_Perf::get_flash_size() - 2 * this->flash_sector_size; }{ ... } esp_err_t WL_Ext_Safe::recover() { esp_err_t result = ESP_OK; // read WL_Ext_Safe_State from flash memory at buff_trans_state_addr WL_Ext_Safe_State state; result = this->read(this->buff_trans_state_addr, &state, sizeof(WL_Ext_Safe_State)); WL_EXT_RESULT_CHECK(result); ESP_LOGV(TAG, "%s recover, start_addr = 0x%08" PRIx32 ", sector_base_addr = 0x%08" PRIx32 ", sector_base_addr_offset= %" PRIu32 ", count=%" PRIu32, __func__, state.sector_restore_sign, state.sector_base_addr, state.sector_base_addr_offset, state.count); // check if we have any incomplete transaction pending. if (state.sector_restore_sign == WL_EXT_SAFE_OK) { // recover data from dump_addr and store it to temporary storage sector_buffer. result = this->read(this->dump_addr, this->sector_buffer, this->flash_sector_size); WL_EXT_RESULT_CHECK(result); //erase complete flash sector result = this->erase_sector(state.sector_base_addr); WL_EXT_RESULT_CHECK(result); /* Restore data which was previously stored to sector_buffer back to data area provided by WL_Ext_Safe_State state *//* ... */ for (int i = 0; i < this->flash_fat_sector_size_factor; i++) { if ((i < state.sector_base_addr_offset) || (i >= state.count + state.sector_base_addr_offset)) { result = this->write(state.sector_base_addr * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size); WL_EXT_RESULT_CHECK(result); }{...} }{...} // clear the buffer transaction state after the data recovery. result = this->erase_range(this->buff_trans_state_addr, this->flash_sector_size); }{...} return result; }{ ... } /* erase_sector_fit function is needed in case flash_sector_size != fat_sector_size and sector to be erased is not multiple of flash_fat_sector_size_factor *//* ... */ esp_err_t WL_Ext_Safe::erase_sector_fit(uint32_t first_erase_sector, uint32_t count) { esp_err_t result = ESP_OK; uint32_t flash_sector_base_addr = first_erase_sector / this->flash_fat_sector_size_factor; uint32_t pre_check_start = first_erase_sector % this->flash_fat_sector_size_factor; // Except pre check and post check data area, read and store all other data to sector_buffer ESP_LOGV(TAG, "%s first_erase_sector=0x%08" PRIx32 ", count = %" PRIu32, __func__, first_erase_sector, count); for (int i = 0; i < this->flash_fat_sector_size_factor; i++) { if ((i < pre_check_start) || (i >= count + pre_check_start)) { result = this->read(flash_sector_base_addr * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size); WL_EXT_RESULT_CHECK(result); }{...} }{...} // For safety purpose store temporary stored data sector_buffer to flash memory at dump_addr result = this->erase_sector(this->dump_addr / this->flash_sector_size); WL_EXT_RESULT_CHECK(result); result = this->write(this->dump_addr, this->sector_buffer, this->flash_sector_size); WL_EXT_RESULT_CHECK(result); //store transaction buffer state to flash memory at buff_trans_state_addr WL_Ext_Safe_State state; state.sector_restore_sign = WL_EXT_SAFE_OK; state.sector_base_addr = flash_sector_base_addr; state.sector_base_addr_offset = pre_check_start; state.count = count; result = this->erase_sector(this->buff_trans_state_addr / this->flash_sector_size); WL_EXT_RESULT_CHECK(result); result = this->write(this->buff_trans_state_addr + 0, &state, sizeof(WL_Ext_Safe_State)); WL_EXT_RESULT_CHECK(result); //erase complete flash sector which includes pre and post check data area result = this->erase_sector(flash_sector_base_addr); WL_EXT_RESULT_CHECK(result); /* Restore data which was previously stored to sector_buffer back to data area which was not part of pre and post check data *//* ... */ for (int i = 0; i < this->flash_fat_sector_size_factor; i++) { if ((i < pre_check_start) || (i >= count + pre_check_start)) { result = this->write(flash_sector_base_addr * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size); WL_EXT_RESULT_CHECK(result); }{...} }{...} // clear the buffer transaction state after data is restored properly. result = this->erase_sector(this->buff_trans_state_addr / this->flash_sector_size); WL_EXT_RESULT_CHECK(result); return ESP_OK; }{ ... }
Details