> 文档中心 > OpenHarmony 的helloWorld尝试

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

第一次代码尝试

创建代码

  1. 在该目录下(OpenHarmony/applications/sample/wifi-iot/app/)创建文件夹 例如该文件夹为 owCode

  2. 在该文件夹下创建一个.c 文件和一个 BUILD.gn 文件

  3. .c 文件这样写,例如该文件为 owCode.c

    #include#include "ohos_init.h"#include "demosdk.h"// 在openharmony中自己新建的函数名不能用mainvoid function(void) {    printf("helloWorld");}SYS_RUN(function);  // 系统跑起来后,调用运行自定义的函数// 不写这个你的函数就不会运行
  4. 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 中 // 代表 源码根目录下

修改配置

  1. 在(OpenHarmony/applications/sample/wifi-iot/app/)找到 BUILD.gn

  2. 修改BUILD.gn,告诉系统那个文件要被编译进去

    import("//build/lite/config/component/lite_component.gni")lite_component("app") {    features = [    # 只修改这里面 "owCode:library",   # 引号内部 (冒号的前面是文件夹名称冒号后面是静态库名称)  # "startup",    ]} 

启动流程分析

hi3861 的 kernel 用的 lite_m 已经烧进去ROM了,我们不能再修改了

所以我们主要是看一下启动后的入口函数

  1. 内核启动以后, 第一个入口函数 hi_void app_main(hi_void)

这个函数会打印 sdk版本号,最后一行还会调用 OHOS_Main()

  1. OHOS_Main() 会调用 OHOS_SystemInit()

  2. 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设备开发第三期)