1 /*
2 * Copyright (c) 2014-2018, Armink, <armink.ztl@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * 'Software'), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Function: Environment variables operating interface. (normal mode)
24 * Created on: 2014-10-06
25 */
26
27 #include <easyflash.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #ifdef EF_USING_ENV
32
33 #ifndef EF_ENV_USING_WL_MODE
34
35 /**
36 * ENV area has 2 sections
37 * 1. System section
38 * It storage ENV parameters. (Units: Word)
39 * 2. Data section
40 * It storage all ENV. Storage format is key=value\0.
41 * All ENV must be 4 bytes alignment. The remaining part must fill '\0'.
42 *
43 * @note Word = 4 Bytes in this file
44 * @note It will has two ENV areas(Area0, Area1) when used power fail safeguard mode.
45 */
46
47 /* flash ENV parameters index and size in system section */
48 enum {
49 /* data section ENV end address index in system section */
50 ENV_PARAM_INDEX_END_ADDR = 0,
51
52 #ifdef EF_ENV_USING_PFS_MODE
53 /* saved count for ENV area */
54 ENV_PARAM_INDEX_SAVED_COUNT,
55 #endif
56
57 /* data section CRC32 code index in system section */
58 ENV_PARAM_INDEX_DATA_CRC,
59 /* flash ENV parameters word size */
60 ENV_PARAM_WORD_SIZE,
61 /* flash ENV parameters byte size */
62 ENV_PARAM_BYTE_SIZE = ENV_PARAM_WORD_SIZE * 4,
63 };
64
65 /* default ENV set, must be initialized by user */
66 static ef_env const *default_env_set;
67 /* default ENV set size, must be initialized by user */
68 static size_t default_env_set_size = 0;
69 /* ENV ram cache */
70 static uint32_t env_cache[ENV_USER_SETTING_SIZE / 4] = { 0 };
71 /* ENV start address in flash */
72 static uint32_t env_start_addr = 0;
73 /* ENV ram cache has changed when ENV created, deleted and changed value. */
74 static bool env_cache_changed = false;
75 /* initialize OK flag */
76 static bool init_ok = false;
77
78 #ifdef EF_ENV_USING_PFS_MODE
79 /* current load ENV area address */
80 static uint32_t cur_load_area_addr = 0;
81 /* next save ENV area address */
82 static uint32_t next_save_area_addr = 0;
83 #endif
84
85 static uint32_t get_env_system_addr(void);
86 static uint32_t get_env_data_addr(void);
87 static uint32_t get_env_end_addr(void);
88 static void set_env_end_addr(uint32_t end_addr);
89 static EfErrCode write_env(const char *key, const char *value);
90 static char *find_env(const char *key);
91 static EfErrCode del_env(const char *key);
92 static size_t get_env_data_size(void);
93 static size_t get_env_user_used_size(void);
94 static EfErrCode create_env(const char *key, const char *value);
95 static uint32_t calc_env_crc(void);
96 static bool env_crc_is_ok(void);
97
98 /**
99 * Flash ENV initialize.
100 *
101 * @param default_env default ENV set for user
102 * @param default_env_size default ENV set size
103 *
104 * @note user_size must equal with total_size in normal mode
105 *
106 * @return result
107 */
ef_env_init(ef_env const * default_env,size_t default_env_size)108 EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size)
109 {
110 EfErrCode result = EF_NO_ERR;
111
112 EF_ASSERT(ENV_AREA_SIZE);
113 EF_ASSERT(ENV_USER_SETTING_SIZE);
114 EF_ASSERT(EF_ERASE_MIN_SIZE);
115 /* must be word alignment for ENV */
116 EF_ASSERT(ENV_USER_SETTING_SIZE % 4 == 0);
117 EF_ASSERT(ENV_AREA_SIZE % 4 == 0);
118 EF_ASSERT(default_env);
119 EF_ASSERT(default_env_size < ENV_USER_SETTING_SIZE);
120
121 #ifndef EF_ENV_USING_PFS_MODE
122 /* total_size must be aligned with erase_min_size */
123 if (ENV_USER_SETTING_SIZE % EF_ERASE_MIN_SIZE == 0)
124 EF_ASSERT(ENV_USER_SETTING_SIZE == ENV_AREA_SIZE);
125 else
126 EF_ASSERT((ENV_USER_SETTING_SIZE / EF_ERASE_MIN_SIZE + 1)*EF_ERASE_MIN_SIZE == ENV_AREA_SIZE);
127 #else
128 /* total_size must be aligned with erase_min_size */
129 if (ENV_USER_SETTING_SIZE % EF_ERASE_MIN_SIZE == 0) {
130 /* it has double area when used power fail safeguard mode */
131 EF_ASSERT(2 * ENV_USER_SETTING_SIZE == ENV_AREA_SIZE);
132 } else {
133 /* it has double area when used power fail safeguard mode */
134 EF_ASSERT(2 * (ENV_USER_SETTING_SIZE / EF_ERASE_MIN_SIZE + 1)*EF_ERASE_MIN_SIZE == ENV_AREA_SIZE);
135 }
136 #endif
137
138 env_start_addr = EF_START_ADDR;
139 default_env_set = default_env;
140 default_env_set_size = default_env_size;
141
142 EF_DEBUG("ENV start address is 0x%08X, size is %d bytes.\n", EF_START_ADDR, ENV_AREA_SIZE);
143
144 result = ef_load_env();
145
146 if (result == EF_NO_ERR)
147 init_ok = true;
148
149 return result;
150 }
151
152 /**
153 * ENV set default.
154 *
155 * @return result
156 */
ef_env_set_default(void)157 EfErrCode ef_env_set_default(void)
158 {
159 EfErrCode result = EF_NO_ERR;
160 size_t i;
161
162 EF_ASSERT(default_env_set);
163 EF_ASSERT(default_env_set_size);
164
165 /* lock the ENV cache */
166 ef_port_env_lock();
167
168 /* set environment end address is at data section start address */
169 set_env_end_addr(get_env_data_addr());
170
171 #ifdef EF_ENV_USING_PFS_MODE
172 /* set saved count to default 0 */
173 env_cache[ENV_PARAM_INDEX_SAVED_COUNT] = 0;
174 #endif
175
176 /* create default ENV */
177 for (i = 0; i < default_env_set_size; i++)
178 create_env(default_env_set[i].key, default_env_set[i].value);
179
180 /* unlock the ENV cache */
181 ef_port_env_unlock();
182
183 result = ef_save_env();
184
185 #ifdef EF_ENV_USING_PFS_MODE
186 /* reset other PFS area's data */
187 if (result == EF_NO_ERR) {
188 env_cache_changed = true;
189 result = ef_save_env();
190 }
191 #endif
192
193
194 return result;
195 }
196
197 /**
198 * Get ENV system section start address.
199 *
200 * @return system section start address
201 */
get_env_system_addr(void)202 static uint32_t get_env_system_addr(void)
203 {
204 #ifndef EF_ENV_USING_PFS_MODE
205 return env_start_addr;
206 #else
207 return cur_load_area_addr;
208 #endif
209 }
210
211 /**
212 * Get ENV data section start address.
213 *
214 * @return data section start address
215 */
get_env_data_addr(void)216 static uint32_t get_env_data_addr(void)
217 {
218 return get_env_system_addr() + ENV_PARAM_BYTE_SIZE;
219 }
220
221 /**
222 * Get ENV end address.
223 * It's the first word in ENV.
224 *
225 * @return ENV end address
226 */
get_env_end_addr(void)227 static uint32_t get_env_end_addr(void)
228 {
229 /* it is the first word */
230 return env_cache[ENV_PARAM_INDEX_END_ADDR];
231 }
232
233 /**
234 * Set ENV end address.
235 * It's the first word in ENV.
236 *
237 * @param end_addr ENV end address
238 */
set_env_end_addr(uint32_t end_addr)239 static void set_env_end_addr(uint32_t end_addr)
240 {
241 env_cache[ENV_PARAM_INDEX_END_ADDR] = end_addr;
242 }
243
244 /**
245 * Get current ENV data section size.
246 *
247 * @return size
248 */
get_env_data_size(void)249 static size_t get_env_data_size(void)
250 {
251 if (get_env_end_addr() > get_env_data_addr())
252 return get_env_end_addr() - get_env_data_addr();
253 else
254 return 0;
255 }
256
257 /**
258 * Get current user used ENV size.
259 *
260 * @return bytes
261 */
get_env_user_used_size(void)262 static size_t get_env_user_used_size(void)
263 {
264 if (get_env_end_addr() > get_env_system_addr())
265 return get_env_end_addr() - get_env_system_addr();
266 else
267 return 0;
268 }
269
270 /**
271 * Get current ENV already write bytes.
272 *
273 * @return write bytes
274 */
ef_get_env_write_bytes(void)275 size_t ef_get_env_write_bytes(void)
276 {
277 #ifndef EF_ENV_USING_PFS_MODE
278 return get_env_user_used_size();
279 #else
280 return get_env_user_used_size() * 2;
281 #endif
282 }
283
284 /**
285 * Write an ENV at the end of cache.
286 *
287 * @param key ENV name
288 * @param value ENV value
289 *
290 * @return result
291 */
write_env(const char * key,const char * value)292 static EfErrCode write_env(const char *key, const char *value)
293 {
294 EfErrCode result = EF_NO_ERR;
295 size_t key_len = strlen(key), value_len = strlen(value), env_str_len;
296 char *env_cache_bak = (char *)env_cache;
297
298 /* calculate ENV storage length, contain '=' and '\0'. */
299 env_str_len = key_len + value_len + 2;
300 if (env_str_len % 4 != 0)
301 env_str_len = (env_str_len / 4 + 1) * 4;
302 /* check capacity of ENV */
303 if (env_str_len + get_env_user_used_size() >= ENV_USER_SETTING_SIZE)
304 return EF_ENV_FULL;
305
306 /* calculate current ENV ram cache end address */
307 env_cache_bak += get_env_user_used_size();
308
309 /* copy key name */
310 memmove(env_cache_bak, key, key_len);
311 env_cache_bak += key_len;
312 /* copy equal sign */
313 *env_cache_bak = '=';
314 env_cache_bak++;
315 /* copy value */
316 memmove(env_cache_bak, value, value_len);
317 env_cache_bak += value_len;
318 /* fill '\0' for string end sign */
319 *env_cache_bak = '\0';
320 env_cache_bak ++;
321 /* fill '\0' for word alignment */
322 memset(env_cache_bak, 0, env_str_len - (key_len + value_len + 2));
323 set_env_end_addr(get_env_end_addr() + env_str_len);
324 /* ENV ram cache has changed */
325 env_cache_changed = true;
326
327 return result;
328 }
329
330 /**
331 * Find ENV.
332 *
333 * @param key ENV name
334 *
335 * @return found ENV in ram cache
336 */
find_env(const char * key)337 static char *find_env(const char *key)
338 {
339 char *env_start, *env_end, *env, *found_env = NULL;
340 size_t key_len = strlen(key), env_len;
341
342 if ((key == NULL) || (*key == 0)) {
343 EF_INFO("Flash ENV name must be not empty!\n");
344 return NULL;
345 }
346
347 /* from data section start to data section end */
348 env_start = (char *)((char *) env_cache + ENV_PARAM_BYTE_SIZE);
349 env_end = (char *)((char *) env_cache + get_env_user_used_size());
350
351 /* ENV is null */
352 if (env_start == env_end)
353 return NULL;
354
355 env = env_start;
356 while (env < env_end) {
357 /* the key length must be equal */
358 if (!strncmp(env, key, key_len) && (env[key_len] == '=')) {
359 found_env = env;
360 break;
361 } else {
362 /* calculate ENV length, contain '\0'. */
363 env_len = strlen(env) + 1;
364 /* next ENV and word alignment */
365 if (env_len % 4 == 0)
366 env += env_len;
367 else
368 env += (env_len / 4 + 1) * 4;
369 }
370 }
371 return found_env;
372 }
373
374 /**
375 * If the ENV is not exist, create it.
376 * @see flash_write_env
377 *
378 * @param key ENV name
379 * @param value ENV value
380 *
381 * @return result
382 */
create_env(const char * key,const char * value)383 static EfErrCode create_env(const char *key, const char *value)
384 {
385 EfErrCode result = EF_NO_ERR;
386
387 EF_ASSERT(key);
388 EF_ASSERT(value);
389
390 if ((key == NULL) || (*key == 0)) {
391 EF_INFO("Flash ENV name must be not empty!\n");
392 return EF_ENV_NAME_ERR;
393 }
394
395 if (strchr(key, '=')) {
396 EF_INFO("Flash ENV name can't contain '='.\n");
397 return EF_ENV_NAME_ERR;
398 }
399
400 /* find ENV */
401 if (find_env(key)) {
402 EF_INFO("The name of \"%s\" is already exist.\n", key);
403 return EF_ENV_NAME_EXIST;
404 }
405 /* write ENV at the end of cache */
406 result = write_env(key, value);
407
408 return result;
409 }
410
411 /**
412 * Delete an ENV in cache.
413 *
414 * @param key ENV name
415 *
416 * @return result
417 */
del_env(const char * key)418 static EfErrCode del_env(const char *key)
419 {
420 EfErrCode result = EF_NO_ERR;
421 char *del_env = NULL;
422 size_t del_env_length, remain_env_length;
423
424 EF_ASSERT(key);
425
426 if ((key == NULL) || (*key == 0)) {
427 EF_INFO("Flash ENV name must be not NULL!\n");
428 return EF_ENV_NAME_ERR;
429 }
430
431 if (strchr(key, '=')) {
432 EF_INFO("Flash ENV name or value can't contain '='.\n");
433 return EF_ENV_NAME_ERR;
434 }
435
436 /* find ENV */
437 del_env = find_env(key);
438
439 if (!del_env) {
440 EF_INFO("Not find \"%s\" in ENV.\n", key);
441 return EF_ENV_NAME_ERR;
442 }
443 del_env_length = strlen(del_env);
444 /* '\0' also must be as ENV length */
445 del_env_length ++;
446 /* the address must multiple of 4 */
447 if (del_env_length % 4 != 0)
448 del_env_length = (del_env_length / 4 + 1) * 4;
449 /* calculate remain ENV length */
450 remain_env_length = get_env_data_size()
451 - (((uint32_t) del_env + del_env_length) - ((uint32_t) env_cache + ENV_PARAM_BYTE_SIZE));
452 /* remain ENV move forward */
453 memmove(del_env, del_env + del_env_length, remain_env_length);
454 /* reset ENV end address */
455 set_env_end_addr(get_env_end_addr() - del_env_length);
456 /* ENV ram cache has changed */
457 env_cache_changed = true;
458
459 return result;
460 }
461
462 /**
463 * Set an ENV. If it value is empty, delete it.
464 * If not find it in ENV table, then create it.
465 *
466 * @param key ENV name
467 * @param value ENV value
468 *
469 * @return result
470 */
ef_set_env(const char * key,const char * value)471 EfErrCode ef_set_env(const char *key, const char *value)
472 {
473 EfErrCode result = EF_NO_ERR;
474 char *old_env, *old_value;
475
476 if (!init_ok) {
477 EF_INFO("ENV isn't initialize OK.\n");
478 return EF_ENV_INIT_FAILED;
479 }
480
481 /* lock the ENV cache */
482 ef_port_env_lock();
483
484 /* if ENV value is empty, delete it */
485 if ((value == NULL) || (*value == 0))
486 result = del_env(key);
487 else {
488 old_env = find_env(key);
489 /* If find this ENV, then compare the new value and old value. */
490 if (old_env) {
491 /* find the old value address */
492 old_env = strchr(old_env, '=');
493 old_value = old_env + 1;
494 /* If it is changed then delete it and recreate it */
495 if (strcmp(old_value, value)) {
496 result = del_env(key);
497 if (result == EF_NO_ERR)
498 result = create_env(key, value);
499 }
500 } else
501 result = create_env(key, value);
502 }
503 /* unlock the ENV cache */
504 ef_port_env_unlock();
505
506 return result;
507 }
508
509 /**
510 * Get an ENV value by key name.
511 *
512 * @param key ENV name
513 *
514 * @return value
515 */
ef_get_env(const char * key)516 char *ef_get_env(const char *key)
517 {
518 char *env = NULL, *value = NULL;
519
520 if (!init_ok) {
521 EF_INFO("ENV isn't initialize OK.\n");
522 return NULL;
523 }
524
525 /* find ENV */
526 env = find_env(key);
527
528 if (env == NULL)
529 return NULL;
530 /* get value address */
531 value = strchr(env, '=');
532 if (value != NULL) {
533 /* the equal sign next character is value */
534 value++;
535 }
536 return value;
537 }
538 /**
539 * Print ENV.
540 */
ef_print_env(void)541 void ef_print_env(void)
542 {
543 uint32_t *env_cache_data_addr = env_cache + ENV_PARAM_WORD_SIZE,
544 *env_cache_end_addr =
545 (uint32_t *)(env_cache + ENV_PARAM_WORD_SIZE + get_env_data_size() / 4);
546 uint8_t j;
547 char c;
548
549 if (!init_ok) {
550 EF_INFO("ENV isn't initialize OK.\n");
551 return;
552 }
553
554 for (; env_cache_data_addr < env_cache_end_addr; env_cache_data_addr += 1) {
555 for (j = 0; j < 4; j++) {
556 c = (*env_cache_data_addr) >> (8 * j);
557 ef_print("%c", c);
558 if (c == 0) {
559 ef_print("\n");
560 break;
561 }
562 }
563 }
564
565 #ifndef EF_ENV_USING_PFS_MODE
566 ef_print("\nENV size: %ld/%ld bytes.\n", get_env_user_used_size(), ENV_USER_SETTING_SIZE);
567 #else
568 ef_print("\nENV size: %ld/%ld bytes, write bytes %ld/%ld, saved count: %ld, mode: power fail safeguard.\n",
569 get_env_user_used_size(), ENV_USER_SETTING_SIZE, ef_get_env_write_bytes(),
570 ENV_AREA_SIZE, env_cache[ENV_PARAM_INDEX_SAVED_COUNT]);
571
572 #endif
573 }
574
575 /**
576 * Load flash ENV to ram.
577 *
578 * @return result
579 */
580 #ifndef EF_ENV_USING_PFS_MODE
ef_load_env(void)581 EfErrCode ef_load_env(void)
582 {
583 EfErrCode result = EF_NO_ERR;
584 uint32_t *env_cache_bak, env_end_addr;
585
586 /* read ENV end address from flash */
587 ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_END_ADDR * 4, &env_end_addr, 4);
588 /* if ENV is not initialize or flash has dirty data, set default for it */
589 if ((env_end_addr == 0xFFFFFFFF) || (env_end_addr < env_start_addr)
590 || (env_end_addr > env_start_addr + ENV_USER_SETTING_SIZE))
591 result = ef_env_set_default();
592 else {
593 /* set ENV end address */
594 set_env_end_addr(env_end_addr);
595
596 env_cache_bak = env_cache + ENV_PARAM_WORD_SIZE;
597 /* read all ENV from flash */
598 ef_port_read(get_env_data_addr(), env_cache_bak, get_env_data_size());
599 /* read ENV CRC code from flash */
600 ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_DATA_CRC * 4,
601 &env_cache[ENV_PARAM_INDEX_DATA_CRC], 4);
602 /* if ENV CRC32 check is fault, set default for it */
603 if (!env_crc_is_ok()) {
604 EF_INFO("Warning: ENV CRC check failed. Set it to default.\n");
605 result = ef_env_set_default();
606 }
607 }
608 return result;
609 }
610 #else
ef_load_env(void)611 EfErrCode ef_load_env(void)
612 {
613 EfErrCode result = EF_NO_ERR;
614 uint32_t area0_start_address = env_start_addr, area1_start_address = env_start_addr
615 + ENV_AREA_SIZE / 2;
616 uint32_t area0_end_addr, area1_end_addr, area0_crc, area1_crc, area0_saved_count, area1_saved_count;
617 bool area0_is_valid = true, area1_is_valid = true;
618 /* read ENV area end address from flash */
619 ef_port_read(area0_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area0_end_addr, 4);
620 ef_port_read(area1_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area1_end_addr, 4);
621 if ((area0_end_addr == 0xFFFFFFFF) || (area0_end_addr < area0_start_address)
622 || (area0_end_addr > area0_start_address + ENV_USER_SETTING_SIZE))
623 area0_is_valid = false;
624 if ((area1_end_addr == 0xFFFFFFFF) || (area1_end_addr < area1_start_address)
625 || (area1_end_addr > area1_start_address + ENV_USER_SETTING_SIZE))
626 area1_is_valid = false;
627 /* check area0 CRC when it is valid */
628 if (area0_is_valid) {
629 /* read ENV area0 crc32 code from flash */
630 ef_port_read(area0_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area0_crc, 4);
631 /* read ENV from ENV area0 */
632 ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address);
633 /* current load ENV area address is area0 start address */
634 cur_load_area_addr = area0_start_address;
635 if (!env_crc_is_ok())
636 area0_is_valid = false;
637 }
638 /* check area1 CRC when it is valid */
639 if (area1_is_valid) {
640 /* read ENV area1 crc32 code from flash */
641 ef_port_read(area1_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area1_crc, 4);
642 /* read ENV from ENV area1 */
643 ef_port_read(area1_start_address, env_cache, area1_end_addr - area1_start_address);
644 /* current load ENV area address is area1 start address */
645 cur_load_area_addr = area1_start_address;
646 if (!env_crc_is_ok())
647 area1_is_valid = false;
648 }
649 /* all ENV area CRC is OK then compare saved count */
650 if (area0_is_valid && area1_is_valid) {
651 /* read ENV area saved count from flash */
652 ef_port_read(area0_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4,
653 &area0_saved_count, 4);
654 ef_port_read(area1_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4,
655 &area1_saved_count, 4);
656 /* the bigger saved count area is valid */
657 if ((area0_saved_count > area1_saved_count) || ((area0_saved_count == 0) && (area1_saved_count == 0xFFFFFFFF)))
658 area1_is_valid = false;
659 else
660 area0_is_valid = false;
661 }
662 if (area0_is_valid) {
663 /* current load ENV area address is area0 start address */
664 cur_load_area_addr = area0_start_address;
665 /* next save ENV area address is area1 start address */
666 next_save_area_addr = area1_start_address;
667 /* read all ENV from area0 */
668 ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address);
669 } else if (area1_is_valid) {
670 /* next save ENV area address is area0 start address */
671 next_save_area_addr = area0_start_address;
672 } else {
673 /* current load ENV area address is area1 start address */
674 cur_load_area_addr = area1_start_address;
675 /* next save ENV area address is area0 start address */
676 next_save_area_addr = area0_start_address;
677 /* set the ENV to default */
678 result = ef_env_set_default();
679 }
680 return result;
681 }
682 #endif
683
684 /**
685 * Save ENV to flash.
686 */
ef_save_env(void)687 EfErrCode ef_save_env(void)
688 {
689 EfErrCode result = EF_NO_ERR;
690 uint32_t write_addr, write_size;
691
692 /* ENV ram cache has not changed don't need to save */
693 if (!env_cache_changed)
694 return result;
695
696 #ifndef EF_ENV_USING_PFS_MODE
697 write_addr = get_env_system_addr();
698 write_size = get_env_user_used_size();
699 /* calculate and cache CRC32 code */
700 env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc();
701 #else
702 write_addr = next_save_area_addr;
703 write_size = get_env_user_used_size();
704 /* replace next_save_area_addr with cur_load_area_addr */
705 next_save_area_addr = cur_load_area_addr;
706 cur_load_area_addr = write_addr;
707 /* change the ENV end address to next save area address */
708 set_env_end_addr(write_addr + write_size);
709 /* ENV area saved count +1 */
710 env_cache[ENV_PARAM_INDEX_SAVED_COUNT]++;
711 /* calculate and cache CRC32 code */
712 env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc();
713 #endif
714
715 /* erase ENV */
716 result = ef_port_erase(write_addr, write_size);
717 switch (result) {
718 case EF_NO_ERR: {
719 EF_INFO("Erased ENV OK.\n");
720 break;
721 }
722 case EF_ERASE_ERR: {
723 EF_INFO("Error: Erased ENV fault! Start address is 0x%08X, size is %ld.\n", write_addr, write_size);
724 /* will return when erase fault */
725 return result;
726 }
727 default:
728 break;
729 }
730
731 /* write ENV to flash */
732 result = ef_port_write(write_addr, env_cache, write_size);
733 switch (result) {
734 case EF_NO_ERR: {
735 EF_INFO("Saved ENV OK.\n");
736 break;
737 }
738 case EF_WRITE_ERR: {
739 EF_INFO("Error: Saved ENV fault! Start address is 0x%08X, size is %ld.\n", write_addr, write_size);
740 break;
741 }
742 default:
743 break;
744 }
745
746 env_cache_changed = false;
747
748 return result;
749 }
750
751 /**
752 * Calculate the cached ENV CRC32 value.
753 *
754 * @return CRC32 value
755 */
calc_env_crc(void)756 static uint32_t calc_env_crc(void)
757 {
758 uint32_t crc32 = 0;
759
760 /* Calculate the ENV end address CRC32. The 4 is ENV end address bytes size. */
761 crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_END_ADDR], 4);
762
763 #ifdef EF_ENV_USING_PFS_MODE
764 /* Calculate the ENV area saved count CRC32. */
765 crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_SAVED_COUNT], 4);
766 #endif
767
768 /* Calculate the all ENV data CRC32. */
769 crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_WORD_SIZE], get_env_data_size());
770
771 EF_DEBUG("Calculate ENV CRC32 number is 0x%08X.\n", crc32);
772
773 return crc32;
774 }
775
776 /**
777 * Check the ENV CRC32
778 *
779 * @return true is ok
780 */
env_crc_is_ok(void)781 static bool env_crc_is_ok(void)
782 {
783 if (calc_env_crc() == env_cache[ENV_PARAM_INDEX_DATA_CRC]) {
784 EF_DEBUG("Verify ENV CRC32 result is OK.\n");
785 return true;
786 } else
787 return false;
788 }
789
790 /**
791 * Set and save an ENV. If set ENV is success then will save it.
792 *
793 * @param key ENV name
794 * @param value ENV value
795 *
796 * @return result
797 */
ef_set_and_save_env(const char * key,const char * value)798 EfErrCode ef_set_and_save_env(const char *key, const char *value)
799 {
800 EfErrCode result = EF_NO_ERR;
801
802 result = ef_set_env(key, value);
803
804 if (result == EF_NO_ERR)
805 result = ef_save_env();
806
807 return result;
808 }
809
810 #endif /* EF_ENV_USING_WL_MODE */
811
812 #endif /* EF_USING_ENV */
813