哈喽大家好,这是该系列博文的第一篇~ 篇~ 一、前言拿到恒玄的SDK源码之后,结合文档花了一些时间研究,这篇就先介绍下代码的框架和模块之间的解耦处理。 二、代码架构1、 根据SDK的目录可以看出,BES采用的是RXT RTOS(嵌入式实时操作系统),并且用了ARM的CMSIS_RTOS API接口;
 2、 我们知道程序运行开始的地方是RTX_CM_LIB.H里面的_main_init(),主要是进行内核初始化、堆栈的设置、main线程的创建和开启内核等。
 3、 第一个线程os_thread_def_main就是main,接着看,在main.cpp文件中。
 4、 app_os_init()里有线程创建,这是CMSIS的风格,开发过STM32应该比较熟悉,用来定义线程、定时器和邮箱通讯等; app_thread_tid = osThreadCreate(osThread(app_thread), NULL);
 5、 app_thread为线程loop函数,OSThread其实是一个宏,就是取地址而已 #define osThread(name) &os_thread_def_##name
 一般在文件开头会看到这样的定义:osThreadDef其实也是一个宏 osThreadDef(app_thread, osPriorityHigh, 1, 2048, “app_thread”);
 这里就是给一个结构体变量初始化赋值,然后把os_thread_def_app_thread的地址传给os_thread()。结构体类型是:
 所以OSThreadDef是设置线程名、优先级以及堆栈大小,通过osThread获取配置的结构体变量的指针,然后作为参数传入OSThreadCreate()。 6、 以上创建了另一个重要线程:app_thread,这个线程将是以后应用模块修改与添加的主要线程。 7、 下面我们看一下app_thread线程里面的具体做了什么: if (mod_handler[msg_p->mod_id]) int ret = mod_handler[msg_p->mod_id] (&(msg_p->msg_body));
 8、 我们可以看到在app_thread线程中,通过app_mailbox_get()反复的在获取邮箱信息,并传入mod_handler[]里面。 static APP_MOD_HANDLER_T mod_handler[APP_MODUAL_NUM];
 看其数据类型是一个函数指针数组,再看其数组下标的定义:

 9、 全局搜索mod_handler,会找到app_set_threadhandle()接口。
 到此,我们了解了各个模块会注册自己的回调函数,然后app_thread()会根据get的消息回调模块对应的API进行处理。 10、 我们现在选取一个模块APP_MODUAL_BATTERY(APP_MODULE_BATTERY),从app_set_threadhandle的调用入手,继续研究模块的架构。
 可以看到app_battery_open()接口里调用了 app_set_threadhandle(APP_MODUAL_BATTERY, app_battery_handle_process); 其中,app_battery_handle_process()就是BATTERY模块的回调处理函数。 11、 app_battery_open()是由app_init()调用,初始化battery模块。其中battery模块用到的全局变量为
 从变量的初始化,我们看到定制化的设置都在tgt_hardware.h里面,还有其他定制化的设置。
 12、 在app_battery_handle_process()里面,我们可以看到:
 通过全局搜索APP_BATTERY_STATUS_OVERVOLT,发现是通过app_battery_irqhandler发出的事件
 app_battery_measure.cb在app_battery_open()中有定义: app_battery_measure.cb = app_battery_event_process;
 上图可以看到是通过app_battery_event_process把模块的消息放到邮箱中。 13、 回到app_battery_irqhandler()

 通过搜索,我们发现app_battery_timer_handler是定时器APP_BATTERY的回调函数, 至此,就搞明白了battery模块的流程: app_battery_open()配置定时器,对结构体进行初始化,注册事件回调和模块处理函数 —>定时调用app_battery_timer_handler()来获取电池的电压值 —>再通过app_battery_irqhandler()将转换之后的电压值与初始值比较,通过 app_battery_event_process发出不同的电池状态 —>在app_battery_event_process()把消息放入邮箱中 —>最后app_thread线程取出消息,调用对应模块的app_battery_handle_process()接口进行处理 14、 我们再回到app_battery_timer_handler()看下hal_gpadc_open()接口。
 可以看到,传入的回调函数指针,赋值给了 gpadc_event_cb[channel] ,另外,用到驱动的地方,要加互斥锁。 15、 通过搜索gpadc_event_cb,进入hal_gpadc_irq_handler()接口;
 通过上图,看到 gpadc_event_cb调用了app_battery_irqhandler,并传入了ADC扫描的值。 16、 继续往下就是hal_gpadc_adc2volt()——> hal_gpadc_adc2volt_calib()等ADC底层接口
 17、 另外,通过搜索hal_gpadc_irq_handler()接口,也可以找到hal_gpadc_irq_control()中断获取的流程
 三、后续扩展类比BATTERY模块,可以继续学习其他模块,比如按键、BT都是同样的机制。
|