鸿蒙wifi iot初始化分析
文章目录1 背景2 开发板系统的入口app_main3 鸿蒙初始化4 模块的初始化5 参考资料1 背景学习一个系统,先从启动过程开始。鸿蒙的wifiiot的初始化过程,涉及的文件并不多,但因为用到了一些复杂一些的宏定义,理解起来比较困难。2 开发板系统的入口app_main文件:vendor/hisi/hi3861/hi3861/app/wifiiot_app/src/app_main.c鸿蒙wi
1 背景
学习一个系统,先从启动过程开始。鸿蒙的wifiiot的初始化过程,涉及的文件并不多,但因为用到了一些复杂一些的宏定义,理解起来比较困难。
2 开发板系统的入口app_main
文件:vendor/hisi/hi3861/hi3861/app/wifiiot_app/src/app_main.c
鸿蒙wifiiot为单进程系统,整个系统的入口程序为app_main,但这个并没有找到明确的文档说明。
这件文件一开始部分,是定义了开发板相关的一些硬件设备的初始化过程,而最后一行,才真正进入鸿蒙操作系统的初始化。
void __attribute__((weak)) HOS_SystemInit(void)
{
return;
}
hi_void app_main(hi_void)
{
const hi_char* sdk_ver = hi_get_sdk_version();
printf("sdk ver:%s\r\n", sdk_ver);
hi_flash_partition_table *ptable = HI_NULL;
peripheral_init();
peripheral_init_no_sleep();
hi_u32 ret = hi_factory_nv_init(HI_FNV_DEFAULT_ADDR, HI_NV_DEFAULT_TOTAL_SIZE, HI_NV_DEFAULT_BLOCK_SIZE);
/* partion table should init after factory nv init. */
ret = hi_flash_partition_init();
ptable = hi_get_partition_table();
ret = hi_nv_init(ptable->table[HI_FLASH_PARTITON_NORMAL_NV].addr, ptable->table[HI_FLASH_PARTITON_NORMAL_NV].size,
HI_NV_DEFAULT_BLOCK_SIZE);
/* if not use file system, there is no need init it */
hi_fs_init();
(hi_void)hi_event_init(APP_INIT_EVENT_NUM, HI_NULL);
hi_sal_init();
/* 此处设为TRUE后中断中看门狗复位会显示复位时PC值,但有复位不完全风险,量产版本请务必设为FALSE */
hi_syserr_watchdog_debug(HI_FALSE);
/* 默认记录宕机信息到FLASH,根据应用场景,可不记录,避免频繁异常宕机情况损耗FLASH寿命 */
hi_syserr_record_crash_info(HI_TRUE);
hi_lpc_init();
hi_lpc_register_hw_handler(config_before_sleep, config_after_sleep);
/* 如果不需要使用Histudio查看WIFI驱动运行日志等,无需初始化diag */
/* if not use histudio for diagnostic, diag initialization is unnecessary */
/* Shell and Diag use the same uart port, only one of them can be selected */
#ifndef CONFIG_FACTORY_TEST_MODE
(hi_void)hi_shell_init();
tcpip_init(NULL, NULL);
ret = hi_wifi_init(APP_INIT_VAP_NUM, APP_INIT_USR_NUM);
HOS_SystemInit();
}
这里有一个小技巧,HOS_SystemInit本地已有一个空定义了,它怎么会调用到操作系统的初始化函数里呢。
这个主要是编译宏__attribute__((weak)) 在起作用,这告诉编译器,这是一个弱引用,如果有其他的HOS_SystemInit的定义,优先用其他部分的。
3 鸿蒙初始化
文件:base/startup/services/bootstrap_lite/source/system_init.c
这里宏的引用特别复杂,宏的定义在:base/startup/services/bootstrap_lite/source/core_main.h
void HOS_SystemInit(void)
{
MODULE_INIT(bsp);
MODULE_INIT(device);
MODULE_INIT(core);
SYS_INIT(service);
SYS_INIT(feature);
MODULE_INIT(run);
SAMGR_Bootstrap();
}
对于MODULE_INIT(run),实际展开后的代码如下:
对于0-4的优先级不同的run段,分别取段首和段尾,然后依次执行段中定义的函数指针。
但这里有一个问题,这些函数指针在哪里进行初始化呢?这就汲及到各个模块的初始化定义代码。
do {
do {
InitCall *initcall = (InitCall *) (__section_begin(".zinitcall." "run" "0" ".init"));
InitCall *initend = (InitCall *) (__section_end(".zinitcall." "run" "0" ".init"));
for (; initcall < initend; initcall++) { (*initcall)(); }
}
while (0);
do {
InitCall *initcall = (InitCall *) (__section_begin(".zinitcall." "run" "1" ".init"));
InitCall *initend = (InitCall *) (__section_end(".zinitcall." "run" "1" ".init"));
for (; initcall < initend; initcall++) { (*initcall)(); }
}
while (0);
do {
InitCall *initcall = (InitCall *) (__section_begin(".zinitcall." "run" "2" ".init"));
InitCall *initend = (InitCall *) (__section_end(".zinitcall." "run" "2" ".init"));
for (; initcall < initend; initcall++) { (*initcall)(); }
}
while (0);
do {
InitCall *initcall = (InitCall *) (__section_begin(".zinitcall." "run" "3" ".init"));
InitCall *initend = (InitCall *) (__section_end(".zinitcall." "run" "3" ".init"));
for (; initcall < initend; initcall++) { (*initcall)(); }
}
while (0);
do {
InitCall *initcall = (InitCall *) (__section_begin(".zinitcall." "run" "4" ".init"));
InitCall *initend = (InitCall *) (__section_end(".zinitcall." "run" "4" ".init"));
for (; initcall < initend; initcall++) { (*initcall)(); }
}
while (0);
}
while (0);
4 模块的初始化
如下文件中,只是定了一个SYS_RUN,但并没有修改上面二个章节提到的启动函数,为什么它就可以在初始化的时候并调用到了呢?
applications/sample/wifi-iot/app/demolink/helloworld.c:24:SYS_RUN(DemoSdkMain);
applications/sample/wifi-iot/app/iothardware/led_example.c:86:SYS_RUN(LedExampleEntry);
applications/sample/wifi-iot/app/samgr/bootstrap_example.c:206:SYS_RUN(MRun);
代码如下:
#include "ohos_init.h"
#include "demosdk.h"
void DemoSdkMain(void)
{
DemoSdkEntry();
}
SYS_RUN(DemoSdkMain);
这里的一切,还是编译宏在启作用,宏定义文件: utils/native/lite/include/hos_init.h
具体的宏我们就不看了,还是直接看展开后的代码,可以看到,它定义了一个函数指针__zinitcall_run_DemoSdkMain,实际指向函数DemoSdkMain,它存储在(".zinitcall." “run” “2” “.init”)的section中,正是上面鸿蒙初始化时用到的优先有为2的section. 当HOS_SystemInit在调用时,则会获取到此sections里的函数指针,并进行调用。
void DemoSdkMain(void)
{
std::cout << "DemoSdkMain" << std::endl;
};
static const InitCall __attribute__((used)) __zinitcall_run_DemoSdkMain __attribute__((section(".zinitcall." "run" "2" ".init"))) = DemoSdkMain;
5 参考资料
更多推荐
所有评论(0)