OpenHarmony源码结构概览
是OpenHarmony 实现了 ARCH(架构)、soc(芯片)、board(开发板)3 层隔离,降低了代码的耦合性。设计比较合理。
# OpenHarmony 文件夹下的目录
├── applications # 该文件夹存放应用相关代码,后续我们编写代码需要在该文件夹下添加。
├── ark
├── base #基础软件子系统 IOT硬件子系统
├── build #组件化编译,构建和配置脚本
├── developtools
├── device # 是具体开发板、芯片相关的源码
├── docs # 说明文档
├── domains #增强软件服务子系统集
├── drivers # 驱动子系统
├── foundation #系统基础能力子系统集
├── interface
├── kernel # 内核子系统 hi3861 用的 liteos_m
├── out # out 文件夹是在编译过后才出现的
├── prebuilts # 编译器及 工具链子系统
├── productdefine
├── test # 测试子系统
├── third_party # 第三方的代码(后续移植开源代码使用)
├── utils # 常用的工具集
└── vendor # 供应商 存放的是厂商相关的配置,包括组件配置、HDF 相关配置
applications
# applications/sample/wifi-iot/app/ 文件夹下的 目录
.
├── BUILD.gn #决定了该目录下那些代码可以编译进固件当中去
├── demolink
├── iothardware
├── samgr
└── startup
device
# device文件夹下的目录
.
├── board # 开发板相关的代码
│ ├── bearpi
│ ├── fnlink
│ ├── goodix
│ └── hisilicon
├── hihope
│ ├── build
│ ├── hardware
│ ├── picture
│ └── rk3568
├── qemu
│ ├── arm_mps2_an386
│ ├── arm_mps3_an547
│ ├── arm_virt
│ ├── drivers
│ ├── esp32
│ ├── hardware
│ ├── riscv32_virt
│ └── SmartL_E802
└── soc #具体芯片的相关代码,芯片的相关驱动
├── bestechnic
├── goodix
└── hisilicon
# 将 soc 和 board 区分开来 实现soc代码可复用
# 后续可能 一个soc 对应多个 board 的情况
kernel
# kernel(内核)文件夹下的 目录
.
├── linux
├── liteos_a
└── liteos_m #hi3861 使用的内核 已提前烧写我们不能再修改
liteos_m
#liteos_m 文件夹下的目录
.
├── arch # 该文件夹存放具体芯片架构的代码,文件夹路径
├── components
├── drivers
├── figures
├── kal
├── kernel
├── targets
├── testsuites
├── tools
└── utils
arch
# arch 文件夹下 的目录
.
├── arm
│ ├── arm9
│ ├── cortex-m3
│ ├── cortex-m33
│ ├── cortex-m4
│ ├── cortex-m55
│ ├── cortex-m7
│ └── include
├── csky
│ └── v2
├── include
├── risc-v
│ ├── nuclei
│ └── riscv32
└── xtensa
└── lx6
vendor
# vendor(供应商) 文件夹下的目录
├── bearpi #小熊派
├── bestechnic #恒玄科技
├── goodix #汇顶科技
├── hihope #润和
├── hisilicon #海思
└── ohemu # 社区自行开发
hi3861的配置文件
OpenHarmony/vendor/hisilicon/hispark_pegasus
.
├── BUILD.gn
├── config.json hi3861的配置文件
├── hals
│ ├── audio
│ │ └── product.gni
│ └── utils
│ ├── sys_param
│ │ ├── BUILD.gn
│ │ └── hal_sys_param.c
│ └── token
│ ├── BUILD.gn
│ └── hal_token.c
└── ohos.build
hisilicon
# hisilicon 文件夹下的目录
├── Hi3516DV300
│ ├── hals
│ ├── hdf_config
│ └── power_config
├── hispark_aries
│ ├── hals
│ ├── hdf_config
│ ├── init_configs
│ └── kernel_configs
├── hispark_pegasus # hi3861 开发板对应的是 hispark_pegasuk_pegasus
│ └── hals
├── hispark_taurus
│ ├── hals
│ ├── hdf_config
│ ├── init_configs
│ └── kernel_configs
├── hispark_taurus_linux
│ ├── hals
│ ├── hdf_config
│ └── init_configs
└── watchos
├── hals
├── hdf_config
└── patchs
hispark_pegasus
# hispark_pegasus 文件夹 下的目录
.
├── BUILD.gn
├── config.json # 配置文件里面定义了内核类型,和使用了哪些子系统
├── hals
│ ├── audio
│ └── utils
└── ohos.build
第一次代码尝试
创建代码
-
在该目录下(OpenHarmony/applications/sample/wifi-iot/app/)创建文件夹 例如该文件夹为 owCode
-
在该文件夹下创建一个.c 文件和一个 BUILD.gn 文件
-
.c 文件这样写,例如该文件为 owCode.c
#include<stdio.h> #include "ohos_init.h" #include "demosdk.h" // 在openharmony中自己新建的函数名不能用main void function(void) { printf("helloWorld"); } SYS_RUN(function); // 系统跑起来后,调用运行自定义的函数 // 不写这个你的函数就不会运行
-
BUILD.gn 文件这样写
# 静态库名称是 library,这个名字自定义
static_library("library") {
# 静态库library 包含了哪些源代码
sources = [ # 里面的内容距离行首是 4个空格
"owCode.c"
]
# 源文件里面头文件的路径
include_dirs = [
"//utils/native/lite/include", # ohos_init.h 所在位置
"//domains/iot/link/libbuild" # demosdk.h 所在位置
]
}
# //domains/iot/link/libbuild 中 // 代表 源码根目录下
修改配置
-
在(OpenHarmony/applications/sample/wifi-iot/app/)找到 BUILD.gn
-
修改BUILD.gn,告诉系统那个文件要被编译进去
import("//build/lite/config/component/lite_component.gni") lite_component("app") { features = [ # 只修改这里面 "owCode:library", # 引号内部 (冒号的前面是文件夹名称冒号后面是静态库名称) # "startup", ] }
启动流程分析
hi3861 的 kernel 用的 lite_m 已经烧进去ROM了,我们不能再修改了
所以我们主要是看一下启动后的入口函数
- 内核启动以后, 第一个入口函数 hi_void app_main(hi_void)
这个函数会打印 sdk版本号,最后一行还会调用 OHOS_Main()
-
OHOS_Main() 会调用 OHOS_SystemInit()
-
OHOS_SystemInit()会进行鸿蒙系统 的初始化
下面是这几个函数的所在c 文件的路径
OpenHarmony/device/soc/hisilicon/hi3861v100/sdk_liteos/app/wifiiot_app/src$
.
├── app_demo_upg_verify.c
├── app_demo_upg_verify.h
├── app_main.c //这个目录下的hi_void app_main(hi_void)
├── blackbox_adapter_impl.c
├── ohos_main.c //OHOS_Main()
├── ohos_main.h
└── SConscript
OpenHarmony/base/startup/bootstrap_lite/services/source
.
├── bootstrap_service.c
├── bootstrap_service.h
├── BUILD.gn
├── core_main.h
└── system_init.c # OHOS_SystemInit(void)
下面我贴出 几个函数的具体情况
// hi_void app_main(hi_void)
hi_void app_main(hi_void)
{
#ifdef CONFIG_FACTORY_TEST_MODE
printf("factory test mode!\r\n");
#endif
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();
#ifndef CONFIG_FACTORY_TEST_MODE
hi_lpc_register_wakeup_entry(peripheral_init);
#endif
hi_u32 ret = hi_factory_nv_init(HI_FNV_DEFAULT_ADDR, HI_NV_DEFAULT_TOTAL_SIZE, HI_NV_DEFAULT_BLOCK_SIZE);
if (ret != HI_ERR_SUCCESS) {
printf("factory nv init fail\r\n");
}
/* partion table should init after factory nv init. */
ret = hi_flash_partition_init();
if (ret != HI_ERR_SUCCESS) {
printf("flash partition table init fail:0x%x \r\n", ret);
}
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 (ret != HI_ERR_SUCCESS) {
printf("nv init fail\r\n");
}
#ifndef CONFIG_FACTORY_TEST_MODE
hi_upg_init();
#endif
/* 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);
#if defined(CONFIG_AT_COMMAND) || defined(CONFIG_FACTORY_TEST_MODE)
ret = hi_at_init();
if (ret == HI_ERR_SUCCESS) {
hi_at_sys_cmd_register();
}
#endif
/* 如果不需要使用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
#ifndef ENABLE_SHELL_DEBUG
#ifdef CONFIG_DIAG_SUPPORT
(hi_void)hi_diag_init();
#endif
#else
(hi_void)hi_shell_init();
#endif
tcpip_init(NULL, NULL);
#endif
ret = hi_wifi_init(APP_INIT_VAP_NUM, APP_INIT_USR_NUM);
if (ret != HISI_OK) {
printf("wifi init failed!\n");
} else {
printf("wifi init success!\n");
}
app_demo_task_release_mem(); /* 释放系统栈内存所使用任务 */
#ifndef CONFIG_FACTORY_TEST_MODE
app_demo_upg_init();
#ifdef CONFIG_HILINK
ret = hilink_main();
if (ret != HISI_OK) {
printf("hilink init failed!\n");
} else {
printf("hilink init success!\n");
}
#endif
#endif
OHOS_Main();
}
// OHOS_Main()
//
void OHOS_Main()
{
#if defined(CONFIG_AT_COMMAND) || defined(CONFIG_FACTORY_TEST_MODE)
hi_u32 ret;
ret = hi_at_init();
if (ret == HI_ERR_SUCCESS) {
hi_u32 ret2 = hi_at_register_cmd(G_OHOS_AT_FUNC_TBL, OHOS_AT_FUNC_NUM);
if (ret2 != HI_ERR_SUCCESS) {
printf("Register ohos failed!\n");
}
}
#endif
OHOS_SystemInit();
}
//OHOS_SystemInit(void)
void OHOS_SystemInit(void)
{
MODULE_INIT(bsp);
MODULE_INIT(device);
MODULE_INIT(core);
SYS_INIT(service);
SYS_INIT(feature);
MODULE_INIT(run); // 对应我们的 applications 中SYS_RUN()宏设置的函数名
SAMGR_Bootstrap();
}
BUILD 语法
source 源文件
include_dir 源文件中头文件的位置
deps 导入第三方库
填写的第三方库中BUILD.gn中静态库的名字
排除错误
找不到头文件
编译的时候报错 No such file or directory
find . -name 头文件名
找不到宏
grep 宏 * -R
找不到函数(例如IoTI2cIinit函数)
OpenHarmony/device/soc/hisilicon/hi3861v100/sdk_liteos/build/config/usr_config.mk中有些宏要取消注释