您的位置:首页 > 其它

duBand源码分析-存储部分

2015-08-05 18:08 218 查看

一、编写说明

对duBand源码的存储部分进行分析,本文档用于记录分析过程。

二、源码分析

1. 存储区域划分

在使用nRF Studio进入程序下载时,可以看出,存储区域分为三个Region,如下图所示,分别存在蓝牙协议栈、应用程序和Bootloader。



在APP中,程序存储区域再细分为APP、DATA和SWAP区,通过阅读源码,得知区域图详细划分如下图所示(注意:duBand的设计文档区域划分与源码的不同)。在Bootloader的源码中,APP DATA的大小为42KB,但在APP的源码中,设置着PAGE_NUM_FOR_DATA为32,而NRF51822的页大小为1024 B,因此APP DATA的大小实际为32 KB,还有10 KB的存储空间没有用到。



2. 代码分析

duBand的每一类型的参数存储占用各一个FLASH页面,如ALARM、USER PROFILE、TARGET等,都各占1 KB的存储空间,但实际上只用到少量。接下来以两个实例分析的方式分析存储和读取的代码,以save_alarm()与load_alarm()为例进行分析。

duBand中的数据存储与读取函数使用了一个比较灵活和高效的方法,就是利用memcmp()与memcpy()进行操作。当有数据需要保存时,先将数据从FLASH中读取出来,再通过memcmp()进行比较,如果数据不同,则有必要保存,否则没有更新,则不保存。存储的时候使用memcpy()将新数据复制至缓冲中,再写到FLASH中。

1) save_alarm()

以save_alarm()为例,其代码如下图所示。(1)先定义数据alarm_mem[],用于存放FLASH中读取出来的数据。(2)调用bd_flash_read_page()读取FLASH内容。(3)如果读取出来的闹钟数量与设置的闹钟数量相等,(4)则检测闹钟内容是否有更新,(5)如没有更新,则不需要重新存储,直接return。如有数据更新,则继续运行下去。(6)获取ALARM存储数据的绝对地址。(7)检测FLASH是否已檫除,(8)如未檫除则需要调用ble_flash_page_delay_erase()进行异步存储,这样做的原因是因为檫除操作比较耗时,如果同步去檫除时,会导影响蓝牙程序,因此这个做了一个异步操作,详细参与异步存储。(9)否则调用save_alarms_into_flash()保存ALARM数据。



save_alarms_into_flash()为具体的存储操作函数,如下图所示。(1)定义临时数据alarm_mem[],用于存在数据。(2)将当前ALARM数据复制至alarm_mem[]中。(3)将alarm_mem[]的数据写进FLASH中。



2) load_alarm()

读取参数的函数就比较简单了,因为不涉及长时间的操作,因此不用进行异步处理,如下图所示,(1)先定义存储读取出来的数据的临时数组alarm_mem[]。(2)读取相应FLASH数据至alarm_mem[]中。如果读取失败,则清空ALARM数据,(4)如果读取成功,则将数据复制至ALARM的全局变量中。



3. 异步存储

由于FLASH的擦除操作比较耗时,为了不影响系统的实时性并不影响蓝牙通讯,当需要对FLASH擦除时,存储系统使用了异步处理事件。通过ble_flash_page_delay_erase()将要删除的页面号写入删除队列flash_page_to_erase_Q[]。具体的操作在ble_flash_erase_data_page()中进行,此函数在ble_radio_notification_init()中注册为RADIO回调事件,并由ble_flash_on_radio_active_evt()异步调用。

先来分析ble_flash_page_delay_erase()函数,如下图所示。(1)先判断目标页面是否已经存在擦除队列中,如在,则不作任何处理。(2)判断目标页面是否在APP DATA区域内,否则返回错误。(3)如果RADIO不在工作中时,则马上进行页面擦除并返回。(4)判断擦除队列是否已满,是则返回错误。(5)将目标页面写入擦除队列中。在这个函数内,其实有个陷阱,如上面所描述的第(3)步,如果这里马上删除了的话,就不会调用异步写入(后面分析)的操作,但是这个操作是无伤大雅的,如果蓝牙断开/不工作,也没有存储的必要。



将目标擦除页写入了队列后,在RADIO的ACTIVE回调函数ble_flash_on_radio_active_evt()中,如下图所示,(1)会判断队列中是否有数据和其它一些条件(如RADIO是否正在工作、蓝牙状态),(2)如有数据,则判断是否已经调用异步擦除,(3如没有则进行异步调用。



最终的擦除和更新操作是在ble_flash_erase_data_page()中完成的,此函数由app_sched调度运行。如下图所示,(1)程序先判断蓝牙是否处于工作状态,(2)如果蓝牙空闲,则可以马上进行页面擦除,(3)并调用sync_data_to_flash()更新相应页面的数据。(4)再判断是否还有需要擦除的页面,有则调用app_sched继续调度ble_flash_erase_data_page()并返回。(5)如果蓝牙正在广播或保持长连接状态下,则需要判断inactive_last_time(此值在ble_flash_on_radio_active_evt()中赋值,估计主要是用于检测是否处于有校时间内)是否合法,合法才进行页面擦除并更新相应页面的数据。



数据更新函数sync_data_to_flash()的代码如下图所示,该函数实现比较简单,只是更新不同的页号去调用相应的数据存储函数。



4. 读写校验

读写的校验在底层的函数ble_flash_page_write()和ble_flash_page_read()中实现。由于这是NORDIC提供的操作库函数,因此这里不继续分析下去了,拿来就用就好了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: