OpenHarmony 的helloWorld尝试
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#include "ohos_init.h"#include "demosdk.h"// 在openharmony中自己新建的函数名不能用mainvoid 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 directoryfind . -name 头文件名
找不到宏
grep 宏 * -R
找不到函数(例如IoTI2cIinit函数)
OpenHarmony/device/soc/hisilicon/hi3861v100/sdk_liteos/build/config/usr_config.mk中有些宏要取消注释
(以上参考 华为开发者学堂 润和软件:三周带你上手OpenHarmony设备开发第三期)