輕量帶屏解決方案之恒玄芯片移植案例

本文章基于恒玄科技 BES2600W 芯片的歐智通 Multi-modal V200Z-R 開發(fā)板 躯喇,進行輕量帶屏開發(fā)板的標準移植辫封,開發(fā)了智能開關面板樣例,同時實現(xiàn)了 ace_engine_lite廉丽、arkui_ui_lite倦微、aafwk_liteappexecfwk_lite正压、HDF 等部件基于 OpenHarmony LiteOS-M 內(nèi)核的適配欣福。移植架構上采用 BoardSoC 分離的方案,工具鏈 Newlib C 庫與 Musl C 庫可選焦履,LiteOS-M 內(nèi)核編譯采用 gn 結合 Kconfig 圖形化配置等需求拓劝。

編譯構建

目錄規(guī)劃

本案例在芯片移植架構方面進行了一些改進,以前的芯片適配目錄規(guī)劃為:

device
└── <device_company>
    └── <device_name>

這樣會導致嘉裤,小熊派 BearPi-HM Nano 開發(fā)板與潤和的 HiSpark Pegasus 開發(fā)板使用小海思的 hi3861SoC 時郑临,需要在這兩款開發(fā)板里面都放置一份重復的代碼。為了解決該問題屑宠,本案例將單板廠商與 SoC 廠商進行分離厢洞,并把芯片適配目錄規(guī)劃為:

device
├── board                                --- 單板廠商目錄
│   └── fnlink                           --- 單板廠商名字:歐智通
│       └── v200zr                       --- 單板名:v200zr
└── soc                                  --- SoC廠商目錄
    └── bestechnic                       --- SoC廠商名字:恒玄
        └── bes2600                      --- SoC Series名:bes2600是一個系列,里面包含bes2600w等SoC名

產(chǎn)品樣例目錄規(guī)劃為:

vendor
└── bestechnic                           --- 開發(fā)產(chǎn)品樣例廠商目錄典奉,恒玄開發(fā)的帶屏樣例躺翻,因此以bestechnic命名
    └── display_demo                     --- 產(chǎn)品名字:以智能開關面板的帶屏顯示樣例

預編譯適配

在進行移植之前,需要進行預編譯適配卫玖。
預編譯適配主要使用 hb set 命令公你,設置整個項目的根目錄、單板目錄假瞬、產(chǎn)品目錄陕靠、單板公司名等環(huán)境變量,為編譯做準備笨触。
具體的預編譯適配步驟如下:

  1. vendor/bestechnic/display_demo 目錄下新增 config.json 文件懦傍,用于描述這個產(chǎn)品樣例所使用的單板、內(nèi)核等信息芦劣,描述信息可參考如下內(nèi)容:
{
  "product_name": "display_demo",       --- 用于hb set進行選擇時粗俱,顯示的產(chǎn)品名稱
  "type": "mini",                       --- 構建系統(tǒng)的類型,mini/small/standard
  "version": "3.0",                     --- 構建系統(tǒng)的版本虚吟,1.0/2.0/3.0
  "device_company": "fnlink",           --- 單板廠商名寸认,用于編譯時找到/device/board/fnlink目錄
  "board": "v200zr",                    --- 單板名签财,用于編譯時找到/device/board/fnlink/v200zr目錄
  "kernel_type": "liteos_m",            --- 內(nèi)核類型,因為OpenHarmony支持多內(nèi)核偏塞,一塊單板可能適配了多個內(nèi)核唱蒸,所以需要指定某個內(nèi)核進行編譯
  "kernel_version": "3.0.0",            --- 內(nèi)核版本,一塊單板可能適配了多個linux內(nèi)核版本灸叼,所以需要指定某個具體的內(nèi)核版本進行編譯
  "subsystems": [ ]                     --- 選擇所需要編譯構建的子系統(tǒng)
}
  1. device/board/fnlink/v200zr/liteos_m 目錄下新增 config.gni 文件神汹,用于描述這個產(chǎn)品樣例所使用的單板、內(nèi)核等信息古今,描述信息可參考如下內(nèi)容:
# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
kernel_type = "liteos_m"                --- 內(nèi)核類型屁魏,跟config.json中kernel_type對應
# Kernel version.
kernel_version = "3.0.0"                --- 內(nèi)核版本,跟config.json中kernel_version對應
  1. 驗證 hb set 配置是否正確捉腥,輸入 hb set 能夠顯示如下圖片表示配置正確氓拼。

執(zhí)行 hb set 輸入項目根目錄,并且回車抵碟,hb 命令會遍歷所有 //vendor/<product_company>/<product_name> 目錄下的 config.json桃漾,給出可選產(chǎn)品編譯選項,config.jsonproduct_name 用于顯示產(chǎn)品名拟逮,device_companyboard 用于關聯(lián)出 //device/board/<device_company>/<board> 目錄撬统,并且匹配 <any_dir_name>/config.gni 文件,如果能夠匹配多個文件唱歧,表示該單板適配了多個內(nèi)核宪摧,那么可以根據(jù) config.jsonkernel_typekernel_version 來唯一匹配 config.gnikernel_typekernel_version,即可確定了需要編譯適配了哪個內(nèi)核的單板颅崩。

通過 hb env 可以查看選擇出來的預編譯環(huán)境變量几于。

在執(zhí)行 hb build 之前,需要準備好 LiteOS-M 內(nèi)核適配沿后,具體適配步驟請參內(nèi)核移植 沿彭。

內(nèi)核移植

內(nèi)核移植需要完成 LiteOS-M Kconfig 適配、gn 的編譯構建和內(nèi)核啟動最小適配尖滚。

LiteOS-M Kconfig 適配

//kernel/liteos_m 目錄下執(zhí)行 make menuconfig 命令喉刘,完成編譯配置選項的選擇。在 Makefile 文件中漆弄,會將 hb env 的結果轉換成環(huán)境變量睦裳,即 PRODUCT_PATHDEVICE_PATHBOARD_COMPANY撼唾。如下代碼塊所示:

$(foreach line,$(shell hb env | sed 's/\[OHOS INFO\]/ohos/g;s/ /_/g;s/:_/=/g' || true),$(eval $(line)))
ifneq ($(ohos_kernel),liteos_m)
$(error The selected product ($(ohos_product)) is not a liteos_m kernel type product)
endif
--- 將hb env的每一行輸出轉化為變量形式廉邑,例如將[OHOS INFO] device company: fnlink轉換為ohos_device_company=fnlink
……
ifeq ($(BOARD_COMPANY),)
BOARD_COMPANY:=$(ohos_device_company)
endif
……
export BOARD_COMPANY
--- 將ohos_device_company轉化為BOARD_COMPANY環(huán)境變量

//kernel/liteos_m/Kconfig 文件中使用這些導出的環(huán)境變量,Kconfiglib 采用 ulfalizer 開發(fā)基于 python 的版本,里面用到了 orsource 關鍵字蛛蒙,其中 o 表示 optional糙箍,表示這個文件是否存在可選,r 表示 relative牵祟,表示這個文件相對當前文件的相對路徑深夯。

config SOC_COMPANY
    string "SoC company name to locate soc build path"
    help
      This option specifies the SoC company name, used to locate the build path for soc. This option is set by the
      SoC's Kconfig file, and should be exactly the same with SoC company path, and the user should generally avoid
       modifying it via the menu configuration.
orsource "../../device/board/*/Kconfig.liteos_m.shields"                                 --- 將所有擴展板配置信息加載進來,因為單板廠商A提供擴展板可以給單板廠商B使用诺苹,所以這里使用*匹配所有的擴展板咕晋,而非BOARD_COMPANY。另外由于OpenHarmony支持多內(nèi)核設計筝尾,Kconfig文件采用liteos_m作為后綴捡需,在進行單板適配過程中,其他內(nèi)核在適配過程中筹淫,可以使用對應的內(nèi)核名作為后綴名進行擴展。
orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.defconfig.boards"         --- 加載BOARD_COMPANY的所有單板預定義配置
choice
    prompt "Board Selection"
orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.boards"                   --- 提供Board選擇列表
endchoice
orsource "../../device/soc/*/Kconfig.liteos_m.defconfig"                                 --- 加載所有SoC的默認配置定義
choice
    prompt "SoC Series Selection"
orsource "../../device/soc/*/Kconfig.liteos_m.series"                                    --- 提供所有SoC Series選擇列表
endchoice
orsource "../../device/soc/*/Kconfig.liteos_m.soc"                                       --- 加載所有SoC配置

//kernel/liteos_m/Kconfig 文件可以看出需要在 //device/board/fnlink 目錄下新增如下 Kconfig 文件進行適配:

.
├── v200zr                                       --- v200zr單板配置目錄
│   ├── Kconfig.liteos_m.board                   --- 提供v200zr單板的配置選項
│   ├── Kconfig.liteos_m.defconfig.board         --- 提供v200zr單板的默認配置項
│   └── liteos_m
│       └── config.gni
├── Kconfig.liteos_m.boards                      --- 提供fnlink單板廠商下Boards配置信息
├── Kconfig.liteos_m.defconfig.boards            --- 提供fnlink單板廠商下Boards默認配置信息
├── Kconfig.liteos_m.shields                     --- 提供fnlink單板廠商下擴展板配置信息
└── shields                                      --- fnlink單板廠商的擴展板目錄
    ├── v200zr-t0                                --- fnlink單板廠商的擴展板v200zr-t0
    │   ├── Kconfig.liteos_m.defconfig.shield    --- 擴展板v200zr-t0默認配置
    │   └── Kconfig.liteos_m.shield              --- 擴展板v200zr-t0配置信息
    ├── v200zr-t1
    │   ├── Kconfig.liteos_m.defconfig.shield
    │   └── Kconfig.liteos_m.shield
    └── Kconfig.liteos_m.shields

v200zr/Kconfig.liteos_m.board 需要配置選擇該單板的選項呢撞,以及它依賴的 SoC损姜,如下:

config BOARD_v200zr
    bool "select board v200zr"
    depends on SOC_BES2600W      --- v200zr單板用的bes2600w的SoC,只有 bes2600w的SoC被選擇后殊霞,v200zr單板配置選項才可見摧阅,可以被選擇。

v200zr/Kconfig.liteos_m.defconfig.board 需要配置選擇該單板后绷蹲,默認定義 BOARD 的名字為 "v200zr" 棒卷,如下:

if BOARD_v200zr
config BOARD
    string       --- string后沒有帶提示,因此用戶不可見
    default "v200zr"
endif # BOARD_v200zr

//kernel/liteos_m/Kconfig 文件可以看出需要在 //device/soc/bestechnic 目錄下新增如下 Kconfig 文件進行適配:

.
├── bes2600                                  --- bes2600 SoC系列
│   ├── Kconfig.liteos_m.defconfig.bes2600w  --- bestechnic芯片廠商bes2600w SoC Series配置
│   ├── Kconfig.liteos_m.defconfig.series    --- bestechnic芯片廠商bes2600默認配置
│   ├── Kconfig.liteos_m.series              --- bestechnic芯片廠商bes2600 SoC Series配置
│   └── Kconfig.liteos_m.soc                 --- bestechnic芯片廠商bes2600 SoC配置
├── Kconfig.liteos_m.defconfig               --- bestechnic芯片廠商SoC默認配置
├── Kconfig.liteos_m.series                  --- bestechnic芯片廠商SoC Series配置
└── Kconfig.liteos_m.soc                     --- bestechnic芯片廠商 SoC配置

bes2600/Kconfig.liteos_m.series 需要配置 bes2600 SoC series祝钢,以及它的芯片架構等信息比规,如下:

config SOC_SERIES_BES2600            --- 提供bes2600 SoC Series選項
    bool "Bestechnic 2600 Series"
    select ARM                       --- 選擇bes2600后,默認選擇ARM架構
    select SOC_COMPANY_BESTECHNIC    --- 選擇bes2600后拦英,默認選擇bestechnic芯片公司蜒什,驅動會依賴這個宏配置,選擇配置編譯對應廠商的驅動
    select CPU_CORTEX_M33            --- 選擇bes2600后疤估,默認選擇cortex-m33 CPU
    help
        Enable support for Bestechnic 2600 series

bes2600/Kconfig.liteos_m.soc 需要提供 bes2600 SoC series 下有多少個具體的 SoC 可供選擇灾常,如下:

choice
    prompt "Bestechnic 2600 series SoC"
    depends on SOC_SERIES_BES2600    --- 只有選擇了bes2600 Series后,才會出現(xiàn)如下配置選項
config SOC_BES2600W                  --- 增加bes2600w SoC配置選擇項
    bool "SoC BES2600w"
endchoice

bes2600/Kconfig.liteos_m.defconfig.series 需要提供 bes2600 SoC series 選擇后的默認配置铃拇,如下:

if SOC_SERIES_BES2600                            --- 選擇了bes2600 Series后钞瀑,才會增加如下默認配置選項
rsource "Kconfig.liteos_m.defconfig.bes2600w"    --- 增加bes2600w SoC的默認配置
config SOC_SERIES                                --- 增加SOC_SERIES的默認配置
    string
    default "bes2600"
endif

配置完成后,還需要根據(jù) kernel/liteos_m/Makefile 文件配置 make menuconfigdefconfig 保存路徑:

ifeq ($(TEE:1=y),y)
tee = _tee
endif
ifeq ($(RELEASE:1=y),y)
CONFIG ?= $(PRODUCT_PATH)/kernel_configs/release$(tee).config
else
CONFIG ?= $(PRODUCT_PATH)/kernel_configs/debug$(tee).config      --- 配置文件保存在$(CONFIG)中慷荔,由產(chǎn)品最終定義
endif
……
update_config menuconfig:
    $(HIDE)test -f "$(CONFIG)" && cp -v "$(CONFIG)" .config && menuconfig $(args) && savedefconfig --out "$(CONFIG)"

在這個例子中雕什,defconfig 配置路徑為 $(PRODUCT_PATH)/kernel_configs/debug.config,創(chuàng)建該文件后,內(nèi)容為空监徘,產(chǎn)品的目錄文件結構如下:

.
└── display_demo
    ├── config.json
    └── kernel_configs
        └── debug.config

配置完成后晋修,在 kernel/liteos_m 目錄下執(zhí)行 make menuconfig 能夠對 SoC Series/SoC/Board 進行選擇,如下:

結果將自動保存在 $(PRODUCT_PATH)/kernel_configs/debug.config凰盔,下次執(zhí)行 make menuconfig 時會導出保存的結果墓卦。

gn 編譯適配

在上一步 Kconfig 的圖形化配置后,將其生成的配置結果可以作為 gn 編譯的輸入户敬,以控制不同模塊是否編譯落剪。另外為了解決之前 gn 編寫時,隨意 include 的問題尿庐,內(nèi)核編譯做了模塊化編譯的設計忠怖,使得整個編譯邏輯更加清晰。
kernel/liteos_m/BUILD.gn 中抄瑟,指定了 BoardSoC 的編譯入口為 //device/board/fnlink//device/soc/bestechnic凡泣。

deps += [ "http://device/board/$device_company" ]
deps += [ "http://device/soc/$LOSCFG_SOC_COMPANY" ]

//device/board/fnlink/BUILD.gn 中,新增內(nèi)容如下:

if (ohos_kernel_type == "liteos_m") {                    --- 由于多內(nèi)核設計皮假,對于LiteOS-M內(nèi)核適配鞋拟,需要用宏來隔離
  import("http://kernel/liteos_m/liteos.gni")                 --- 引入內(nèi)核gn編寫模板
  module_name = get_path_info(rebase_path("."), "name")  --- 動態(tài)獲取當前文件目錄作為模塊名,防止目錄名修改后惹资,這里還需要跟著修改
  module_group(module_name) {                            --- 采用module_group模板
    modules = [                                          --- 添加需要編譯的模塊
    ]
  }
}

同理 //device/soc/bestechnic/BUILD.gn 也是一樣贺纲。

內(nèi)核啟動適配

系統(tǒng)啟動流程分為三個階段:

階段名稱 分區(qū)規(guī)劃 描述
BOOT1 [0, 0x10000] 第一階段啟動,進行固件啟動
BOOT2 [0x2C010000, 0x2C020000] 第二階段啟動褪测,進行 OTA 升級啟動
RTOS_MAIN [0x2C080000, 0x2C860000] 第三階段啟動猴誊,進行內(nèi)核啟動

在第三階段內(nèi)核啟動中,需要適配的文件路徑在 //device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/rtos/liteos/liteos_m/board.c

內(nèi)核啟動適配總體思路如下:

  1. 中斷向量的初始化 os_vector_init 侮措,初始化中斷的處理函數(shù)懈叹。
  2. 內(nèi)核初始化 osKernelInitialize
  3. 創(chuàng)建線程 board_main萝毛,進行芯片平臺初始化项阴。
  4. 內(nèi)核啟動,開始調(diào)度線程 osKernelStart 笆包。
    其中环揽,本章節(jié)詳細對第 3 步進行展開审洞,其他幾步為對內(nèi)核函數(shù)調(diào)用间护,不作詳細描述。
    第 3 步中 board_main 在啟動 OHOS_SystemInit 之前劝篷,需要初始化必要的動作巴粪,如下:
...
    if(!ret) {
        ...
        OhosSystemAdapterHooks();    --- 系統(tǒng)啟動時候設置鉤子通今,啟動OpenHarmonyOHOS_SystemInit的之前完成打印和驅動的初始化
        ...
        OHOS_SystemInit();           --- 啟動OpenHarmony服務粥谬,以及組件初始化
    }
....

OhosSystemAdapterHooks 函數(shù)在 device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c 文件中,如下:

int OhosSystemAdapterHooks(void)
{
    init_trace_system();     --- 初始化打印函數(shù)
    DeviceManagerStart();    --- 調(diào)用DeviceManagerStart函數(shù)進行HDF驅動初始化辫塌,這個過程會調(diào)用單板代碼中的驅動配置文件hdf.hcs以及drivers源碼實現(xiàn)
    return 0;
}

littlefs 文件系統(tǒng)移植

V200Z-R 開發(fā)板開發(fā)板采用最大 32MB 的支持 XIPNor Flash漏策,文件系統(tǒng)可以使用 example掺喻,適配過程中感耙,需要在指定路徑下放置文件系統(tǒng)預置文件即硼,根據(jù)配置可自動生成文件系統(tǒng)鏡像,可以實現(xiàn)自動化生成和打包到燒錄包中屡拨。

  1. 配置指定目錄放置打包文件系統(tǒng) config.json只酥,通過 flash_partition_dir 指定目錄:
  "flash_partition_dir": "fs"    --- 表示在vendor/bestechnic/display_demo/fs目錄下放置文件系統(tǒng)預置文件
  1. 在指定目錄 vendor/bestechnic/display_demo/fs 下放置兩部分內(nèi)容:
  • wifi_Download_cfg.yaml:鏡像的燒錄配置文件层皱,可以根據(jù)實際情況調(diào)整分區(qū)赠潦。
  • /data/data:第一個/data 是掛載的根目錄;第二個 data 是根目錄里面的 data 目錄草冈,里面可以存放預置文件,或者在第二個 data 的同級目錄再創(chuàng)建一個目錄怎棱,打包的時候只認第一個 data 掛載根目錄哩俭。
  1. config.json 中根據(jù) wifi_Download_cfg.yaml 最后調(diào)整結果。
  • fs_src 配置文件系統(tǒng)掛載名字拳恋。
  • fs_name 是最后生成文件系統(tǒng)的名字凡资。
  • block_size 配置成 4K 對齊,建議不修改谬运。
  • fs_size 是生成文件系統(tǒng)的大小隙赁。
  • burn_name 是燒錄 bin 名字的大小伞访。
  • enable 表示是否生成這個文件系統(tǒng)
  1. //device/soc/bestechnic/bes2600/liteos_m/components/hdf_config/hdf.hcs 文件配置文件系統(tǒng)的燒錄的起始地址轰驳、文件系統(tǒng)的大小以及讀數(shù)據(jù)塊的大小 block_size 等信息,參考配置如下:
    misc {
        fs_config {
            example_config {
                match_attr = "littlefs_config";
                mount_points = ["/data"];
                partitions = [10];
                block_size = [4096];
                block_count = [1024];
            }
        }
        storage_config {
            flash_config {
                match_attr = "flash_config";
                partitions = [10];
                owner = [0];
                description = ["littlefs"];
                start_addr = [0xB60000];
                length = [0x400000];
                options = [3];
            }
        }
    }

最后在 device/soc/bestechnic/bes2600/liteos_m/components/fs/fs_init.c 中昙篙,通過 hdf 加載數(shù)據(jù),進行讀寫 flash,如下:

static int32_t FsDriverInit(struct HdfDeviceObject *object)
{
    if (object == NULL) {
        return HDF_FAILURE;
    }
    if (object->property) {
        if (FsGetResource(fs, object->property) != HDF_SUCCESS) {
            HDF_LOGE("%s: FsGetResource failed", __func__);
            return HDF_FAILURE;
        }
    }
    for (int i = 0; i < sizeof(fs) / sizeof(fs[0]); i++) {
        if (fs[i].mount_point == NULL)
            continue;
        fs[i].lfs_cfg.read = littlefs_block_read;
        fs[i].lfs_cfg.prog = littlefs_block_write;
        fs[i].lfs_cfg.erase = littlefs_block_erase;
        fs[i].lfs_cfg.sync = littlefs_block_sync;
        fs[i].lfs_cfg.read_size = 256;
        fs[i].lfs_cfg.prog_size = 256;
        fs[i].lfs_cfg.cache_size = 256;
        fs[i].lfs_cfg.lookahead_size = 16;
        fs[i].lfs_cfg.block_cycles = 1000;
        int ret = mount(NULL, fs[i].mount_point, "littlefs", 0, &fs[i].lfs_cfg);
        HDF_LOGI("%s: mount fs on '%s' %s\n", __func__, fs[i].mount_point, (ret == 0) ? "succeed" : "failed");
    }
    return HDF_SUCCESS;
}

C 庫適配

在輕量系統(tǒng)中,C 庫適配比較復雜烂瘫,設計思路請參考 LiteOS-M 內(nèi)核支持 musl 與 newlib 平滑切換方案怜校,由于我們的工具鏈采用gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 自帶 newlib 的 C 庫付燥,那么系統(tǒng)移植整體采用 newlib 的 C 庫。那么在內(nèi)核的 make menuconfig 中選擇 newlib叁执,如下圖:

malloc 適配

malloc 適配參考 The Red Hat newlib C Library-malloc 。實現(xiàn) malloc 適配有以下兩種方法:

  • 實現(xiàn) _sbrk_r 函數(shù)滋恬。這種方法中,內(nèi)存分配函數(shù)使用 newlib 中的啸胧。
  • 實現(xiàn) _malloc_r, _realloc_r, _reallocf_r, _free_r, _memalign_r, 和 _malloc_usable_size_r烙博。這種方法中眷唉,內(nèi)存分配函數(shù)可以使用內(nèi)核的。
    為了方便地根據(jù)業(yè)務進行內(nèi)存分配算法調(diào)優(yōu)和問題定位,在這兩種方法中政供,本案例選擇后者。
    首先,由于 newlib 中已經(jīng)存在這些函數(shù)的符號传藏,因此需要用到 gccwrap 的鏈接選項替換這些函數(shù)符號為內(nèi)核的實現(xiàn)试幽,內(nèi)核的實現(xiàn)為 //kernel/liteos_m/kal/libc/newlib/porting/src/malloc.c擒滑。
    然后,在 //device/board/fnlink/v200zr/liteos_m/config.gni 的新增這些函數(shù)的 wrap 鏈接選項。
board_ld_flags += [
     "-Wl,--wrap=_malloc_r",
     "-Wl,--wrap=_realloc_r",
     "-Wl,--wrap=_reallocf_r",
     "-Wl,--wrap=_free_r",
     "-Wl,--wrap=_memalign_r",
     "-Wl,--wrap=_malloc_usable_size_r",
]

vsprintf 等適配

實現(xiàn) vprintf, vfprintf, printf, snprintfsprintf禽最。
類似 malloc 適配疹味,首先要提供這些函數(shù)的實現(xiàn)竟痰,//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/printf.c,本案例直接采用開源協(xié)議友好的實現(xiàn)粘拾。與 malloc 適配不同的是殿雪,這個函數(shù)由芯片原廠提供拯爽。因為就打印來說备禀,根據(jù)項目的需要蛾绎,實現(xiàn)可大可小,內(nèi)核不方便提供統(tǒng)一的實現(xiàn)公荧。
然后朱灿,在 //device/board/fnlink/v200zr/liteos_m/config.gni 的新增這些函數(shù)的 wrap 鏈接選項池户。

board_ld_flags += [
     "-Wl,--wrap=printf",
     "-Wl,--wrap=sprintf",
     "-Wl,--wrap=snprintf",
     "-Wl,--wrap=vsnprintf",
     "-Wl,--wrap=vprintf",
]

open 等適配

這部分實現(xiàn)由內(nèi)核統(tǒng)一實現(xiàn)耸成,芯片適配無須關注,內(nèi)核文件 //kernel/liteos_m/kal/libc/newlib/porting/src/fs.c躺枕,適配了 newlib_read危彩、_write 等函數(shù),如下:

……
ssize_t _read(int fd, void *buf, size_t nbyte)
{
    return LOS_Read(fd, buf, nbyte);
}
ssize_t _write(int fd, const void *buf, size_t nbyte)
{
    return LOS_Write(fd, buf, nbyte);
}
off_t _lseek(int fd, off_t offset, int whence)
{
    return LOS_Lseek(fd, offset, whence);
}
……

板級系統(tǒng)移植

驅動移植

SoC 芯片平臺 HDF 驅動移植

驅動適配相關文件放置在 drivers/adapter/platform 中,對應有 gpio莉掂,i2c喷楣,pwm熊昌,spiuart祖屏,watchdog,都是通過 HDF 機制加載蟹瘾,本章節(jié)以 gpio 為例進行詳細說明。

GPIO 驅動適配

gpio 驅動適配需要完成編譯的適配狠鸳、源碼的適配铅祸。
//drivers/adapter/platform/gpio/BUILD.gn 文件中夜焦,描述了恒玄 gpio 驅動的編譯適配萎津。如下:

module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO)    --- 如果打開HDF的GPIO配置開關荤傲,才進行如下編譯
module_name = get_path_info(rebase_path("."), "name")
hdf_driver(module_name) {
  sources = []
  if (defined(LOSCFG_SOC_COMPANY_BESTECHNIC)) {              --- 如果打開恒玄的芯片配置開關,才進行恒玄GPIO的驅動編譯
    sources += [ "gpio_bes.c" ]
  }
  include_dirs = [ "." ]
}

//drivers/adapter/platform/gpio/gpio_bes.c 文件中雾家,描述了恒玄 gpio 驅動的源碼適配铃彰。
首先,按照 OpenHarmonyHDF 驅動框架加載驅動基本適配框架芯咧,如下:

struct HdfDriverEntry g_GpioDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "BES_GPIO_MODULE_HDF",
    .Bind = GpioDriverBind,
    .Init = GpioDriverInit,
    .Release = GpioDriverRelease,
};
HDF_INIT(g_GpioDriverEntry);     --- 通過HDF_INIT 加載GPIO驅動

然后牙捉,在初始化的時候會獲取 hcs 參數(shù)進行初始化,如下:

static int32_t GpioDriverInit(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct GpioCntlr *gpioCntlr = NULL;
    if (device == NULL) {
        HDF_LOGE("%s: device is NULL", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    gpioCntlr = GpioCntlrFromDevice(device);     --- gpioCntlr節(jié)點變量就可以獲取具體gpio配置
    if (gpioCntlr == NULL) {
      ...

編碼規(guī)范和設計思想見 bes 驅動適配 PR 的評論敬飒。

Board 外設器件 HDF 驅動移植

Board 外設器件表示通過 SoC 平臺總線連接的外設器件邪铲,在本案例中,顯示屏屬于外設器件无拗,其驅動適配放在 //device/board/fnlink/drivers/liteos_m 目錄中霜浴。

顯示驅動適配

SoC 驅動適配,在 //device/board/fnlink/drivers/liteos_m/display/BUILD.gn 文件中蓝纲,根據(jù) hdf_driver 模板加載驅動模塊,如下:

module_name = get_path_info(rebase_path("."), "name")
hdf_driver(module_name) {
  sources = [
    "zzw395.c",
  ]
  include_dirs = [
    "http://drivers/peripheral/display/interfaces/include",
  ...
  ]
}

//device/board/fnlink/drivers/liteos_m/display/zzw395.c 文件中晌纫,根據(jù)驅動框架加載顯示驅動税迷,如下:

static struct HdfDriverEntry g_ZZW395DriverEntry = {
    .moduleVersion = 1,
    .moduleName = "HDF_PANEL_ZZW395",
    .Bind = PanelDriverBind,
    .Init = PanelDriverInit,
    .Release = PanelDriverRelease,
};
HDF_INIT(g_ZZW395DriverEntry);

其中的驅動參數(shù)根據(jù) hcs 配置,在 PanelDriverInit 初始化時加載锹漱,如下:

static int32_t PanelDriverInit(struct HdfDeviceObject *object)
{
    if (object == NULL) {
        return HDF_FAILURE;
    }
    HDF_LOGD("%s entry !!!", __func__);
    if (object->property) {
        if (PanelGetResource(&priv, object->property) != HDF_SUCCESS) {
            HDF_LOGE("%s: PanelGetResource failed", __func__);
            return HDF_FAILURE;
        }
    }
...

OpenHarmony 子系統(tǒng)適配

OpenHarmony 子系統(tǒng)適配一般包含兩部分:

  • config.json 中增加對應子系統(tǒng)和部件箭养,這樣編譯系統(tǒng)會將該部件納入編譯目標中。
  • 針對該部件的 HAL 層接口進行硬件適配哥牍,或者可選的軟件功能適配毕泌。

分布式軟總線子系統(tǒng)適配

wifi_lite 部件適配

首先,在 config.json 文件中嗅辣,增加 communication 子系統(tǒng)的 wifi_lite 部件撼泛,如下:

    {
      "subsystem": "communication",
      "components": [
        {
          "component": "wifi_lite",
          "optional": "true"
        }
      ]
    },

wifi_lite 部件在 //build/lite/components/communication.json 文件中,描述如下:

    {
      "component": "wifi_lite",
……
      "targets": [
        "http://foundation/communication/wifi_lite:wifi"      --- wifi_lite的編譯目標
      ],
……
    },

//foundation/communication/wifi_lite/BUILD.gn 文件中澡谭,描述需要適配的接口頭文件路徑愿题,如下:

config("include") {
  include_dirs = [ "interfaces/wifiservice" ]    --- 因為wifi_lite只提供頭文件,不提供wifi的具體實現(xiàn)蛙奖,所以wifi模塊暴露出適配的目錄路徑提供給硬件廠商來適配潘酗,廠商提供wifi協(xié)議棧源碼實現(xiàn)。
}
group("wifi") {
  public_configs = [ ":include" ]
}

因為在本案例中雁仲,wifi 屬于 SoC 提供的功能仔夺,所以適配源碼放在 SoC//device/soc/bestechnic/hals/communication/wifi_lite/wifiservice 目錄下,包含 wifi_device.cwifi_hotspot.c 分別適配 wifi_device.hwifi_hotspot.h攒砖。如下:

……
WifiErrorCode Scan(void)     --- wifi_device.c中掃描wifi熱點的函數(shù)缸兔,對wifi_device.h中Scan函數(shù)的適配實現(xiàn)
{
    WifiErrorCode ret = ERROR_WIFI_BUSY;
    if (IsWifiActive() != WIFI_STA_ACTIVE)
        return ERROR_WIFI_IFACE_INVALID;
    if (g_HalHmosWifiInfo.scan_state == SCAN_REQUEST ||
        g_HalHmosWifiInfo.scan_state == SCAN_TRIGGER)
        return ERROR_WIFI_BUSY;
    HalHmosWifiLock();
    ret = ((HalHmosSendEvent(HMOS_ON_WIFI_SCAN_STATE_CHANGED, NULL) == 0) ? WIFI_SUCCESS : ERROR_WIFI_BUSY);
    HalHmosWifiUnLock();
    return ret;
}
……
int GetSignalLevel(int rssi, int band)   --- wifi_hotspot.c中獲取wifi信號熱點函數(shù)日裙,對wifi_hotspot.h中GetSignalLevel函數(shù)的適配實現(xiàn)。
{
    if (band == HOTSPOT_BAND_TYPE_2G) {
        if (rssi >= RSSI_LEVEL_4_2_G)
            return RSSI_LEVEL_4;
        if (rssi >= RSSI_LEVEL_3_2_G)
            return RSSI_LEVEL_3;
        if (rssi >= RSSI_LEVEL_2_2_G)
            return RSSI_LEVEL_2;
        if (rssi >= RSSI_LEVEL_1_2_G)
            return RSSI_LEVEL_1;
    }
    if (band == HOTSPOT_BAND_TYPE_5G) {
        if (rssi >= RSSI_LEVEL_4_5_G)
            return RSSI_LEVEL_4;
        if (rssi >= RSSI_LEVEL_3_5_G)
            return RSSI_LEVEL_3;
        if (rssi >= RSSI_LEVEL_2_5_G)
            return RSSI_LEVEL_2;
        if (rssi >= RSSI_LEVEL_1_5_G)
            return RSSI_LEVEL_1;
    }
    return ERROR_WIFI_INVALID_ARGS;
}
LWIP 部件適配

LiteOS-M kernel 目錄下默認配置了 lwip灶体,因而具有編譯功能阅签,可以在 kernel 組件中指定 lwip 編譯的目錄。如下:

    {
      "subsystem": "kernel",
      "components": [
        {
          "component": "liteos_m",
          "features": [
            "ohos_kernel_liteos_m_lwip_path = \"http://device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1\""      --- 指定在芯片廠商目錄中進行適配
          ]
        }
      ]
    },

//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/BUILD.gn 文件中蝎抽,描述了 lwip 的編譯政钟,如下:

import("http://kernel/liteos_m/liteos.gni")
import("$LITEOSTHIRDPARTY/lwip/lwip.gni")
import("$LITEOSTOPDIR/components/net/lwip-2.1/lwip_porting.gni")
module_switch = defined(LOSCFG_NET_LWIP_SACK)
module_name = "lwip"
kernel_module(module_name) {
  sources = LWIP_PORTING_FILES + LWIPNOAPPSFILES -
            [ "$LWIPDIR/api/sockets.c" ] + [ "porting/src/ethernetif.c" ]        --- 增加ethernetif.c文件,用以適配ethernet網(wǎng)卡的初始化適配
  defines = [ "LITEOS_LWIP=1" ]
  defines += [ "CHECKSUM_BY_HARDWARE=1" ]
}
config("public") {
  defines = [ "_BSD_SOURCE=1" ]
  include_dirs =
      [ "porting/include" ] + LWIP_PORTING_INCLUDE_DIRS + LWIP_INCLUDE_DIRS
}

//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/include/lwip/lwipopts.h 文件中樟结,說明原有 lwip 配置選項保持不變养交,軟總線會依賴這些配置選項,并且新增硬件適配的配置項瓢宦,如下:

#ifndef _PORTING_LWIPOPTS_H_
#define _PORTING_LWIPOPTS_H_
#include_next "lwip/lwipopts.h"              --- 保持原來的配置項不變
#define LWIP_NETIF_STATUS_CALLBACK      1
#define LWIP_CHECKSUM_ON_COPY           0
#define CHECKSUM_GEN_UDP                0    --- 新增硬件適配選項
#endif /* _PORTING_LWIPOPTS_H_ */

//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/src/ethernetif.c 文件中碎连,說明對 ethernet 網(wǎng)卡初始化的適配,如下:

err_t
ethernetif_init(struct netif *netif)
{
……
#ifdef CHECKSUM_BY_HARDWARE
    eth_hw_checksum_init();
#endif
……
    netif->linkoutput = low_level_output;
    netif->drv_send = liteos_low_level_output;
    netif->hwaddr_len = NETIF_MAX_HWADDR_LEN;
    low_level_init(netif);
    driverif_init(netif);
    return ERR_OK;
……
}
dsoftbus 部件適配

config.json 中增加 dsoftbus 部件配置如下:

{
  "component": "dsoftbus",
  "features": [
    "softbus_adapter_config = \"http://vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config\""
  ]
},

dsoftbus 部件在 //foundation/communication/dsoftbus/dsoftbus.gni 文件中提供了 softbus_adapter_config 配置選項可供移植過程進行配置驮履,該配置設定了軟總線移植適配的路徑鱼辙。
在本案例中,softbus_adapter_config 配置為 //vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config 路徑玫镐,該路徑下的內(nèi)容為:

.
├── feature_config                  --- 軟總線功能特性配置倒戏,例如是否開啟自發(fā)現(xiàn)功能等
│   └── mini
│       └── config.gni
└── spec_config                     --- 軟總線規(guī)格特性配置,例如設置軟總線日志級別設置
    ├── softbus_config_adapter.c
    ├── softbus_config_adapter.h
    └── softbus_config_type.h

config.gni 文件中規(guī)定了以下配置項:

配置項 描述
dsoftbus_feature_disc_ble 是否開啟 BLE 發(fā)現(xiàn)功能
dsoftbus_feature_disc_coap 是否開啟 COAP 發(fā)現(xiàn)功能
dsoftbus_feature_conn_tcp 是否開啟 TCP 連接功能
dsoftbus_feature_conn_br 是否開啟 BR 連接功能
dsoftbus_feature_conn_ble 是否開啟 BLE 連接功能
dsoftbus_feature_conn_p2p 是否開啟 P2P 連接功能
dsoftbus_feature_trans_udp 是否開啟 UDP 傳輸功能
dsoftbus_feature_trans_udp_stream 是否開啟 UDP 傳輸流功能
dsoftbus_feature_trans_udp_file 是否開啟 UDP 傳輸文件功能
dsoftbus_feature_ip_auth 是否開啟認證傳輸通道功能
dsoftbus_feature_auth_account 是否開啟基于賬號認證功能
dsoftbus_feature_qos 是否開啟 QoS 功能

softbus_config_adapter.c 文件中規(guī)定了以下配置項:

配置項 描述
SOFTBUS_INT_MAX_BYTES_LENGTH SendBytes 發(fā)送最大 Bytes 長度
SOFTBUS_INT_MAX_MESSAGE_LENGTH SendMessage 發(fā)送最大消息的長度
SOFTBUS_INT_CONN_BR_MAX_DATA_LENGTH 藍牙最大接收數(shù)據(jù)量
SOFTBUS_INT_CONN_RFCOM_SEND_MAX_LEN 藍牙最大接收數(shù)據(jù)量
SOFTBUS_INT_ADAPTER_LOG_LEVEL 日志級別設置
SOFTBUS_STR_STORAGE_DIRECTORY 存儲目錄設置

因為軟總線配置了后恐似,不會默認啟動杜跷,所以需要在通過啟動框架調(diào)用 InitSoftBusServer 函數(shù),如下: | |

static void DSoftBus(void)
{
    osThreadAttr_t attr;
    attr.name = "dsoftbus task";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 65536;
    attr.priority = 24;
    extern void InitSoftBusServer(void);
    if (osThreadNew((osThreadFunc_t) InitSoftBusServer, NULL, &attr) == NULL) {
        printf("Failed to create WifiSTATask!\n");
    }
}
APP_FEATURE_INIT(DSoftBus);
RPC 部件適配

config.json 中增加 rpc 部件配置如下:

{
  "component": "rpc"
},

同樣地矫夷,rpc 部件需要通過啟動框架調(diào)用 StartDBinderService 函數(shù)葛闷,由于該函數(shù)正常運行依賴主機已經(jīng)獲取 IP 地址,因此在 LWIP 協(xié)議棧注冊 IP 地址變化事件的回調(diào)函數(shù)中調(diào)用該函數(shù)双藕,如下:

static void RpcServerWifiDHCPSucCB(struct netif *netif, netif_nsc_reason_t reason,
                                   const netif_ext_callback_args_t *args)
{
    (void) args;
    if (netif == NULL) {
        printf("%s %d, error: input netif is NULL!\n", __FUNCTION__, __LINE__);
        return;
    }
    if (reason == LWIP_NSC_IPSTATUS_CHANGE) {
        if (netif_is_up(netif) && !ip_addr_isany(&netif->ip_addr)) {
            printf("%s %d, start rpc server!\n", __FUNCTION__, __LINE__);
            StartDBinderService();
        }
    }
}
static void WifiDHCPRpcServerCB(void)
{
    NETIF_DECLARE_EXT_CALLBACK(WifiReadyRpcServerCallback);
    netif_add_ext_callback(&WifiReadyRpcServerCallback, RpcServerWifiDHCPSucCB);
}
APP_FEATURE_INIT(WifiDHCPRpcServerCB);

啟動恢復子系統(tǒng)適配

啟動恢復子系統(tǒng)適配 bootstrap_lite/syspara_lite 兩個部件淑趾。請在 vendor/bestechnic_bak/display_demo/config.json 中新增對應的配置選項。

{
  "subsystem": "startup",
  "components": [
    {
      "component": "bootstrap_lite"      --- bootstrap_lite 部件
    },
    {
      "component": "syspara_lite",       --- syspara_lite 部件
      "features": [
        "enable_ohos_startup_syspara_lite_use_posix_file_api = true"
      ]
    }
  ]
},

適配 bootstrap_lite 部件時忧陪,需要在連接腳本文件 //device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/out/best2600w_liteos/_best2001.lds 中手動新增如下段:

       __zinitcall_bsp_start = .;
      KEEP (*(.zinitcall.bsp0.init))
      KEEP (*(.zinitcall.bsp1.init))
      KEEP (*(.zinitcall.bsp2.init))
      KEEP (*(.zinitcall.bsp3.init))
      KEEP (*(.zinitcall.bsp4.init))
      __zinitcall_bsp_end = .;
      __zinitcall_device_start = .;
      KEEP (*(.zinitcall.device0.init))
      KEEP (*(.zinitcall.device1.init))
      KEEP (*(.zinitcall.device2.init))
      KEEP (*(.zinitcall.device3.init))
      KEEP (*(.zinitcall.device4.init))
      __zinitcall_device_end = .;
      __zinitcall_core_start = .;
      KEEP (*(.zinitcall.core0.init))
      KEEP (*(.zinitcall.core1.init))
      KEEP (*(.zinitcall.core2.init))
      KEEP (*(.zinitcall.core3.init))
      KEEP (*(.zinitcall.core4.init))
      __zinitcall_core_end = .;
      __zinitcall_sys_service_start = .;
      KEEP (*(.zinitcall.sys.service0.init))
      KEEP (*(.zinitcall.sys.service1.init))
      KEEP (*(.zinitcall.sys.service2.init))
      KEEP (*(.zinitcall.sys.service3.init))
      KEEP (*(.zinitcall.sys.service4.init))
      __zinitcall_sys_service_end = .;
      __zinitcall_sys_feature_start = .;
      KEEP (*(.zinitcall.sys.feature0.init))
      KEEP (*(.zinitcall.sys.feature1.init))
      KEEP (*(.zinitcall.sys.feature2.init))
      KEEP (*(.zinitcall.sys.feature3.init))
      KEEP (*(.zinitcall.sys.feature4.init))
      __zinitcall_sys_feature_end = .;
      __zinitcall_run_start = .;
      KEEP (*(.zinitcall.run0.init))
      KEEP (*(.zinitcall.run1.init))
      KEEP (*(.zinitcall.run2.init))
      KEEP (*(.zinitcall.run3.init))
      KEEP (*(.zinitcall.run4.init))
      __zinitcall_run_end = .;
      __zinitcall_app_service_start = .;
      KEEP (*(.zinitcall.app.service0.init))
      KEEP (*(.zinitcall.app.service1.init))
      KEEP (*(.zinitcall.app.service2.init))
      KEEP (*(.zinitcall.app.service3.init))
      KEEP (*(.zinitcall.app.service4.init))
      __zinitcall_app_service_end = .;
      __zinitcall_app_feature_start = .;
      KEEP (*(.zinitcall.app.feature0.init))
      KEEP (*(.zinitcall.app.feature1.init))
      KEEP (*(.zinitcall.app.feature2.init))
      KEEP (*(.zinitcall.app.feature3.init))
      KEEP (*(.zinitcall.app.feature4.init))
      __zinitcall_app_feature_end = .;
      __zinitcall_test_start = .;
      KEEP (*(.zinitcall.test0.init))
      KEEP (*(.zinitcall.test1.init))
      KEEP (*(.zinitcall.test2.init))
      KEEP (*(.zinitcall.test3.init))
      KEEP (*(.zinitcall.test4.init))
      __zinitcall_test_end = .;
      __zinitcall_exit_start = .;
      KEEP (*(.zinitcall.exit0.init))
      KEEP (*(.zinitcall.exit1.init))
      KEEP (*(.zinitcall.exit2.init))
      KEEP (*(.zinitcall.exit3.init))
      KEEP (*(.zinitcall.exit4.init))
      __zinitcall_exit_end = .;

需要新增上述段是因為 bootstrap_init 提供的對外接口治笨,見 //utils/native/lite/include/ohos_init.h 文件,采用的是灌段的形式赤嚼,最終會保存到上述鏈接段中旷赖。主要的服務自動初始化宏如下表格所示:

接口名 描述
SYS_SERVICE_INIT(func) 標識核心系統(tǒng)服務的初始化啟動入口
SYS_FEATURE_INIT(func) 標識核心系統(tǒng)功能的初始化啟動入口
APP_SERVICE_INIT(func) 標識應用層服務的初始化啟動入口
APP_FEATURE_INIT(func) 標識應用層功能的初始化啟動入口

說明:
通過上面加載的組件編譯出來的 lib 文件需要手動加入強制鏈接。

如在vendor/bestechnic/display_demo/config.json 中配置了 bootstrap_lite 部件

    {
      "subsystem": "startup",
      "components": [
        {
          "component": "bootstrap_lite"
        },
        ...
      ]
    },

bootstrap_lite 部件會編譯 //base/startup/bootstrap_lite/services/source/bootstrap_service.c更卒,該文件中等孵,通過 SYS_SERVICE_INITInit 函數(shù)符號灌段到 __zinitcall_sys_service_start__zinitcall_sys_service_end 中,由于 Init 函數(shù)是沒有顯式調(diào)用它蹂空,所以需要將它強制鏈接到最終的鏡像俯萌。如下:

static void Init(void)
{
    static Bootstrap bootstrap;
    bootstrap.GetName = GetName;
    bootstrap.Initialize = Initialize;
    bootstrap.MessageHandle = MessageHandle;
    bootstrap.GetTaskConfig = GetTaskConfig;
    bootstrap.flag = FALSE;
    SAMGR_GetInstance()->RegisterService((Service *)&bootstrap);
}
SYS_SERVICE_INIT(Init);   --- 通過SYS啟動即SYS_INIT啟動就需要強制鏈接生成的lib

//base/startup/bootstrap_lite/services/source/BUILD.gn 文件中果录,描述了在 out/v200zr/display_demo/libs 生成 libbootstrap.a,如下:

static_library("bootstrap") {
  sources = [
    "bootstrap_service.c",
    "system_init.c",
  ]
  ....

那么需要在vendor/bestechnic/display_demo/config.json 配置強制鏈接庫 bootstrap咐熙,如下:

  "bin_list": [
    {
      "elf_name": "wifiiot",
      "bsp_target_name": "best2600w_liteos",
      "signature": "false",
      "burn_name": "rtos_main",
      "enable": "true",
      "force_link_libs": [
        "bootstrap",     --- 強制鏈接libbootstrap.a
        ...
      ]
    },

適配 syspara_lite 部件時弱恒,系統(tǒng)參數(shù)會最終寫到文件中進行持久化保存。在輕量系統(tǒng)中棋恼,文件操作相關接口有 POSIX 接口與 HalFiles 接口這兩套實現(xiàn)返弹。
因為對接內(nèi)核的文件系統(tǒng),采用 POSIX 相關的接口爪飘,所以 features 字段中需要增加 enable_ohos_startup_syspara_lite_use_posix_file_api = true义起。
如果對接 HalFiles 相關的接口實現(xiàn)的,則無須修改师崎。
在適配 GetSerial 接口時默终,開發(fā)板不像產(chǎn)線生產(chǎn)過程那樣,會寫入一個具體的 Serial Number犁罩,因而需要確定一個數(shù)據(jù)對開發(fā)板進行唯一標識齐蔽。本案例采用 WiFi Mac 地址進行適配。

#define ETH_ALEN 6
#define MAC_BITS 4
#define MAC_HIGH_MASK 0xf0
#define MAC_LOW_MASK 0x0f
#define HEX_A 0xa
#define CHAR_NUM_OFFSET 0x30
#define CHAR_CAPITAL_OFFSET 0x37
#define STR_END_FLAG '\0'
typedef unsigned char               u8;
static char serialNumber[2*ETH_ALEN + 1];        --- 最后一位留作'\0'結束符標識
static char Hex2Char(u8 hex)
{
    if (hex < HEX_A) {
        return hex + CHAR_NUM_OFFSET;            --- 將數(shù)值0轉為char的'0'
    } else {
        return hex + CHAR_CAPITAL_OFFSET;        --- 將數(shù)值0xa轉為char的'A'
    }
}
const char* HalGetSerial(void)
{
    char macAddr[ETH_ALEN];
    // as devboard has no production serial number, we just
    // use wifi mac address as device serial number.
    if (serialNumber[0] == STR_END_FLAG) {       --- 只有第一次調(diào)用時床估,才去獲取mac地址
        extern int bwifi_get_own_mac(u8 *addr);
        bwifi_get_own_mac(macAddr);              --- 獲取mac地址
        int j = 0;
        for (int i = 0; i < ETH_ALEN; i++) {
            u8 lowFour, highFour;
            highFour = (macAddr[i] & MAC_HIGH_MASK) >> MAC_BITS;
            serialNumber[j] = Hex2Char(highFour);
            j++;
            lowFour = macAddr[i] & MAC_LOW_MASK;
            serialNumber[j] = Hex2Char(lowFour);
            j++;
        }        --- 將mac地址值轉化為serial number
    }
    return serialNumber;
}

DFX 子系統(tǒng)適配

進行 DFX 子系統(tǒng)適配需要添加 hilog_lite 部件肴熏,直接在 config.json 文件配置即可。

{
  "subsystem": "hiviewdfx",
  "components": [
    {
      "component": "hilog_lite",
      "optional": "true"
    }
  ]
},

配置完成之后顷窒,在 //device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c 中注冊日志輸出實現(xiàn)函數(shù)。

boolean HilogProc_Impl(const HiLogContent *hilogContent, uint32 len)
{
    char tempOutStr[LOG_FMT_MAX_LEN] = {0};
    if (LogContentFmt(tempOutStr, sizeof(tempOutStr), hilogContent) > 0) {
        printf(tempOutStr);
    }
    return TRUE;   
}
HiviewRegisterHilogProc(HilogProc_Impl);

系統(tǒng)服務管理子系統(tǒng)適配

進行系統(tǒng)服務管理子系統(tǒng)適配需要添加 samgr_lite 部件源哩,直接在 config.json 配置即可鞋吉。

{
  "subsystem": "systemabilitymgr",
  "components": [
    {
      "component": "samgr_lite",
      "features": [
        "config_ohos_systemabilitymgr_samgr_lite_shared_task_size = 4096"
      ]
    }
  ]
},

在輕量系統(tǒng)中,samgr_lite 配置的共享任務棧大小默認為 0x800励烦。當函數(shù)調(diào)用棧較大時谓着,會出現(xiàn)棧溢出的問題。在本次適配過程中坛掠,將其調(diào)整為 0x1000赊锚。

安全子系統(tǒng)適配

進行安全子系統(tǒng)適配需要添加 huks/deviceauth_lite 部件,直接在 config.json 配置即可屉栓。

    {
      "subsystem": "security",
      "components": [
        {
          "component": "huks",
          "features": [
            "huks_use_lite_storage = true",
            "huks_use_hardware_root_key = true",
            "huks_config_file = \"hks_config_lite.h\"",
            "huks_key_store_path = \"/data/\"",
            "ohos_security_huks_mbedtls_porting_path = \"http://device/soc/bestechnic/hals/mbedtls\""
          ]
        },
        {
          "component": "deviceauth_lite",
          "features": [
            "deviceauth_storage_path = \"/data/\"",
            "deviceauth_hichain_thread_stack_size = 9472"
          ]
        }
      ]
    }

huks 部件適配時舷蒲,huks_key_store_path 配置選項用于指定存放秘鑰路徑,ohos_security_huks_mbedtls_porting_path 配置選項用于指定進行 mbedtls 適配的目錄友多,用于芯片對 mbedtls 進行硬件隨機數(shù)等適配牲平。
deviceauth_lite 部件適配時,deviceauth_storage_path 配置選項用于指定存放設備認證信息的路徑域滥,deviceauth_hichain_thread_stack_size 用于指定線程棧大小纵柿。

媒體子系統(tǒng)適配

進行媒體子系統(tǒng)適配需要添加 histreamer 部件蜈抓,直接在 config.json 配置即可。

{
  "subsystem": "multimedia",
  "components": [
    {
      "component": "histreamer",
      "features": [
        "histreamer_enable_plugin_hdi_adapter = true",
        "histreamer_enable_plugin_minimp3_adapter = true",
        "histreamer_enable_plugin_ffmpeg_adapter = false",
        "config_ohos_histreamer_stack_size = 65536"
      ]
    }
  ]
},

histreamer 部件配置項說明如下:

配置項 說明
histreamer_enable_plugin_hdi_adapter 是否使能 histreamer 對接到 hdi 接口
histreamer_enable_plugin_minimp3_adapter 是否使能插件適配 minimp3
histreamer_enable_plugin_ffmpeg_adapter 是否使能插件適配 FFmpeg
config_ohos_histreamer_stack_size histreamer 棧大小設置

公共基礎庫子系統(tǒng)適配

進行公共基礎庫子系統(tǒng)適配需要添加 kv_store/js_builtin/timer_task/kal_timer 部件昂儒,直接在 config.json 配置即可沟使。

{
  "subsystem": "utils",
  "components": [
    {
      "component": "kv_store",
      "features": [
        "enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true"
      ]
    },
    {
      "component": "js_builtin"
    },
    {
      "component": "timer_task"
    },
    {
      "component": "kal_timer",
    }
  ]
},

與適配 syspara_lite 部件類似,適配 kv_store 部件時渊跋,鍵值對會寫到文件中腊嗡。在輕量系統(tǒng)中,文件操作相關接口有 POSIX 接口與 HalFiles 接口這兩套實現(xiàn)刹枉。因為對接內(nèi)核的文件系統(tǒng)叽唱,采用 POSIX 相關的接口,所以 features 需要增加 enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true微宝。如果對接 HalFiles 相關的接口實現(xiàn)的棺亭,則無須修改。

圖形子系統(tǒng)適配

進行圖形子系統(tǒng)適配需要添加 graphic_utils 部件蟋软,直接在 config.json 配置即可镶摘。

    {
      "components": [
        {
          "component": "graphic_utils",
          "features": [
            "enable_ohos_graphic_utils_product_config = true"
          ]
        },
        {
          "component": "ui"
        }
      ]
    },

graphic 配置文件見 //vendor/bestechnic/display_demo/graphic_config/product_graphic_lite_config.h
graphic 適配見 //device/soc/bestechnic/bes2600/liteos_m/components/ui, 主要功能如下:

  • display_device:實例化 BaseGfxEngine岳守。
  • touch_input:實例化 PointerInputDevice凄敢。
  • UiMainTask:初始化字體引擎,執(zhí)行渲染任務等湿痢。
    圖形子系統(tǒng)層次:
aafwk_lite + appexecfwk_lite    (AAFWK + APPEXECFWK)
      |
ace_engine_lite + jerryscript + i18n_lite + resmgr_lite + utils/native/lite/... (ACE,JS引擎及其依賴)
      |
arkui_ui_lite + graphic_utils      (圖形框架)
      |
giflib + libjpeg + libpng + qrcodegen + freetype... (圖形第三方庫)

圖形應用示例見文件 //vendor/bestechnic/display_demo/tests/app.cpp涝缝,如下:

/* ui app entry */
void RunApp()
{
#ifdef UI_TEST
    AnimatorDemoStart();     --- native ui demo
#elif defined(ABILITY_TEST)
    StartJSApp();            --- js demo
#endif
}
void AppEntry(void)
{
    UiMain();
}
APP_FEATURE_INIT(AppEntry);

ACE 開發(fā)框架子系統(tǒng)適配

進行 ACE 開發(fā)框架子系統(tǒng)適配需要添加 ace_engine_lite 部件,直接在 config.json 配置即可譬重。

{
"subsystem": "ace",
"components": [
{
"component": "ace_engine_lite",
"features": [
"enable_ohos_ace_engine_lite_product_config = true"
]
}
]
},

ace_engine_lite 部件配置文件見 //vendor/bestechnic/display_demo/ace_lite_config/product_acelite_config.h拒逮。
ace_lite 的應用采用 js 語言進行開發(fā),詳細步驟如下:

  1. DevEco Studio 編寫 js 應用臀规。
  2. 使用預覽功能進行預覽滩援,并且得到 js 包:entry\.preview\intermediates\res\debug\lite\assets\js\default
  3. 將 js 包放到對應的文件系統(tǒng)目錄下塔嬉,文件系統(tǒng)路徑為 vendor/bestechnic/display_demo/fs/data/data/js玩徊,如下:
├── app.js
├── common
├── i18n
├── manifest.json
└── pages
  1. 最終編譯生成系統(tǒng)鏡像,燒錄到單板后谨究,系統(tǒng)會從 app.js 加載啟動 ace 的應用恩袱。

元能力子系統(tǒng)適配

進行元能力子系統(tǒng)適配需要添加 aafwk_lite 部件,直接在 config.json 配置即可胶哲。

    {
      "subsystem": "aafwk",
      "components": [
        {
          "component": "aafwk_lite",
          "features": [
            "enable_ohos_appexecfwk_feature_ability = true",     --- 支持FA特性憎蛤,即包含圖形能力
            "config_ohos_aafwk_ams_task_size = 4096"             --- 配置aafwk棧的大小
          ]
        }
      ]
    },

aafwk_lite 相關的應用樣例見 vendor/bestechnic/display_demo/tests/ability 目錄,包含 launcherjs app 這兩類應用,應用的函數(shù)調(diào)用流程描述如下:

  1. launcher 應用俩檬,通過 InstallLauncher 安裝 BundleName"com.example.launcher"native ui 應用萎胰,在 AbilityMgrSliteFeature 啟動后會調(diào)用 AbilityMgrHandler::StartLauncher() 啟動 launcher 應用。
  2. StartJSApp 應用棚辽,通過 StartAbility 啟動任意 Want技竟,通過將 want data 傳遞 JS_APP_PATH,
    SetWantData(&want, JS_APP_PATH, strlen(JS_APP_PATH) + 1)

包管理子系統(tǒng)適配

進行包管理子系統(tǒng)適配需要添加 appexecfwk_lite 部件屈藐,直接在 config.json 配置即可榔组。

    {
      "subsystem": "appexecfwk",
      "components": [
        {
          "component": "appexecfwk_lite"
        }
      ]
    },

兼容性認證

XTS 用例

XTS 測試參考資料見 xts 參考資料,進行 XTS 子系統(tǒng)適配需要添加 xts_acts/xts_tools 部件联逻,直接在 config.json 配置即可搓扯,配置如下:

{
"subsystem": "xts",
"components": [
{ "component": "xts_acts", "features":
[
"config_ohos_xts_acts_utils_lite_kv_store_data_path = "/data"",
"enable_ohos_test_xts_acts_use_thirdparty_lwip = true"
]
},
{ "component": "xts_tools", "features":[] }
]
}

其中,

  • config_ohos_xts_acts_utils_lite_kv_store_data_path 是配置掛載文件系統(tǒng)根目錄的名字包归。
  • enable_ohos_test_xts_acts_use_thirdparty_lwip 表示如果使用 thirdparty/lwip 目錄下的源碼編譯锨推,則設置為 true,否則設置為 false公壤。
    全部跑完會有顯示 xx Tests xx Failures xx Ignored换可,如下:
...
[16:53:43:438]../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:793:testKvStoreMaxSize004:PASS
[16:53:43:438]+-------------------------------------------+
[16:53:43:438]
[16:53:43:438]-----------------------
[16:53:43:438]32 Tests 0 Failures 0 Ignored 
[16:53:43:438]OK
[16:53:43:439]All the test suites finished!

報告提交

將上圖 XTS 用例的情況保存為測試報告,上傳到 OpenHarmony 兼容性測試網(wǎng)站進行認證厦幅,作為 sig 倉庫轉正到 master 倉庫的必要條件沾鳄。詳細步驟如下:
步驟 1:將 XTS 測試報告壓縮成 zip 文件。
步驟 2:生成測試報告的 SHA 校驗碼确憨。本案例是將 zip 文件傳到在線生成 hash 的 網(wǎng)站 生成 SHA 校驗碼译荞。
步驟 3:進入 OpenHarmony 兼容性測試網(wǎng)站上傳報告。

  • 其中 API Level 填寫報告中的 "sdkApiLevel" 字段
  • OS 版本號填寫報告中的 "OS Version" 字段休弃。

寫在最后

如果你覺得這篇內(nèi)容對你還蠻有幫助吞歼,我想邀請你幫我三個小忙

  • 點贊,轉發(fā)玫芦,有你們的 『點贊和評論』,才是我創(chuàng)造的動力本辐。
  • 關注小編桥帆,同時可以期待后續(xù)文章ing??,不定期分享原創(chuàng)知識慎皱。
  • 想要獲取更多完整鴻蒙最新學習知識點老虫,請移步前往小編:https://gitee.com/MNxiaona/733GH/blob/master/jianshu
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市茫多,隨后出現(xiàn)的幾起案子祈匙,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夺欲,死亡現(xiàn)場離奇詭異跪帝,居然都是意外死亡,警方通過查閱死者的電腦和手機些阅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門伞剑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人市埋,你說我怎么就攤上這事黎泣。” “怎么了缤谎?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵抒倚,是天一觀的道長。 經(jīng)常有香客問我坷澡,道長托呕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任洋访,我火速辦了婚禮镣陕,結果婚禮上,老公的妹妹穿的比我還像新娘姻政。我一直安慰自己呆抑,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布汁展。 她就那樣靜靜地躺著鹊碍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪食绿。 梳的紋絲不亂的頭發(fā)上侈咕,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音器紧,去河邊找鬼耀销。 笑死,一個胖子當著我的面吹牛铲汪,可吹牛的內(nèi)容都是我干的熊尉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼掌腰,長吁一口氣:“原來是場噩夢啊……” “哼狰住!你這毒婦竟也來了?” 一聲冷哼從身側響起齿梁,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤催植,失蹤者是張志新(化名)和其女友劉穎肮蛹,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體创南,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡伦忠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了扰藕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缓苛。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖邓深,靈堂內(nèi)的尸體忽然破棺而出未桥,到底是詐尸還是另有隱情,我是刑警寧澤芥备,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布冬耿,位于F島的核電站,受9級特大地震影響萌壳,放射性物質(zhì)發(fā)生泄漏亦镶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一袱瓮、第九天 我趴在偏房一處隱蔽的房頂上張望缤骨。 院中可真熱鬧,春花似錦尺借、人聲如沸绊起。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虱歪。三九已至,卻和暖如春栅表,著一層夾襖步出監(jiān)牢的瞬間笋鄙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工怪瓶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萧落,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓洗贰,卻偏偏與公主長得像找岖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哆姻,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容