Starting with ESP8266(4)–User parameters securely save & load on flash

ESP8266 Non-OS SDK开发探坑之四-用户非易失参数安全存储到flash

Brief: This blog will introduce the way to store data onto flash securely without worrying about the unexpected power off. First I will tell you how to locate the space to store user parameters, than I will offer an example to save and load the parameters safely. The consistency of data is guaranteed by the way the official library implement the API — that takes 2 more sectors to save one sector’s data.

Starting with ESP8266 — Light a LED

Starting with ESP8266 (2)–Touch to control relay status-circuit design & electronic components selection

Starting with ESP8266(3) — Touch to control Relay-Programming & PCB design

由于ESP8266系统可以自动保存系统参数到flash完成上电自动选择wifi工作模式和wifi连接参数等,但用户有时也需要保存一些非易失的数据,这就需要用户将信息写入flash,如果进一步考虑,写入flash的时候必须整扇区(4kb)擦除,然后再写入,所以存在一定的时长,如果为了数据完整性、安全性考虑,就必须考虑写入的时候突然掉电的风险。官方对这个问题是有说明的。见文档:

https://www.espressif.com/zh-hans/support/download/documents?keys=&field_type_tid%5B%5D=14

ESP8266 Flash 读写说明

本文先讨论了用户参数存放区域问题,然后调用系统api进行数据安全读写。

首先根据官方的文档

ESP8266 SDK 入门指南

或者结合博文【ESP8266开发入坑1—-点亮LED】提到的flash布局说明,

不支持云端升级(即NON-FOTA)的用户数据在eagle.irom0text.bin之后,而改文件的大小和保存地址在指南里有:

结合这两个文件,我们就可以计算出用户参数区的首地址:

比如512-non-fota,用户数据区首地址 = eagle.irom0text.bin的首地址 0x10000 + 大小 368*1024 = 0x6C000,

而实际用的是扇区数而不是字节地址数,所以需要0x6C000/4096 = 0x5C,

这里计算注意16-10进制转换。同理可以计算出fota布局下的用户参数区地址。

而用户参数区的大小除了首地址外还需要结尾地址决定,这个其实就是RF-CAL区的首地址,也就是blank.bin的存放地址。

我这里都算好了,并利用 user_rf_cal_sector_set里对flash布局的swtich顺便完成了该地址计算:

好了,有了参数保存地址,我们再看看参数的保存和加载吧。

官方SDK API文档有说明其保护机制:

https://www.espressif.com/sites/default/files/2C-ESP8266_Non_OS_SDK_API_Reference__CN.pdf

这个官方有API的我就不造轮子了,如果有更多要求的可以自己实现。

这里我就定义了通用方法放到FlashParam头和实现文件中

先是定义要保存的参数结构体:

其中ConfHolder是方便调试用的, 在user_config.h里有定义这个宏:

每当修改完代码烧录到芯片,如果修改了CONF_HOLDER宏的值,那么从flash读取参数的时候先比对ConfHolder,不一样就会重置系统参数,或者将宏的参数保存,如果不修改,那么就不用重新配置,新烧录的程序继续用之前芯片保存的数据。

所以加载的代码就复杂些了。

WorkStatus的每一位标记一个工作状态信息,方便上电恢复工作状态,这里我的定义是:

分别定义了是否开启web server 、tcp client需要连接的远程服务器信息是否配置等。

RemoteAddr保存了tcp-client需要连接的远程服务器地址信息,RemotePort保存了tcp-client需要连接的远程服务器端口信息,Domain标记远程服务器信息是域名还是ip,其实这个标记有点多余,因为可以对RemodeAddr进行STR->IP的转换或验证,如果失败就按域名进行DNS解析。

后文探坑7就对DNS解析做了解释。

flash参数的加载:

函数如上文完成了CONF_HOLDER的比对和重置,并多此一举的对ssid进行了设置,主要是为了防止固定ssid的重合导致多个设备无法区分,所以根据mac地址映射到了26个字母大小写和10个数字的可视字符,当然base64编码也可以。

密码当然就设成固定的初始密码,如大家有别的需求可以自行替换。

参数保存特别简单:

stFlashProtParam毕竟全局都要用为了方便就弄成了全局变量。

此外,为了大家DIY方便,我将自定义的flash写入方法封装了方便的版本,主要是考虑到原始的FLASH读写接口是按扇区来的,读取还好,写入需要整扇区擦除,然后写入,那么,很容易造成误删数据,所以该函数就将每次擦除和写入操作合并,先读取出整个扇区保存到临时对象,然后修改临时对象,然后正扇区写入,这里有些问题,比如内存空间问题,需要一下子开辟整扇区4KB的栈或堆空间,而且效率也是个问题,用前需要细致考虑下。

代码见:

https://github.com/atp798/BlogStraka/tree/master/ESP8266_NONOS_SDK-2.2.1-WebServer/

 

发表评论