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<stdio.h>
    
    #include "ohos_init.h"
    #include "demosdk.h"
    // 在openharmony中自己新建的函数名不能用main
    void 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 directory
find . -name 头文件名

找不到宏

grep 宏 * -R

找不到函数(例如IoTI2cIinit函数)

OpenHarmony/device/soc/hisilicon/hi3861v100/sdk_liteos/build/config/usr_config.mk中有些宏要取消注释

(以上参考 华为开发者学堂 润和软件:三周带你上手OpenHarmony设备开发第三期)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值