本文章基于恒玄科技 BES2600W
芯片的歐智通 Multi-modal V200Z-R 開發(fā)板 躯喇,進行輕量帶屏開發(fā)板的標準移植辫封,開發(fā)了智能開關面板樣例,同時實現(xiàn)了 ace_engine_lite
廉丽、arkui_ui_lite
倦微、aafwk_lite
、appexecfwk_lite
正压、HDF
等部件基于 OpenHarmony LiteOS-M
內(nèi)核的適配欣福。移植架構上采用 Board
與 SoC
分離的方案,工具鏈 Newlib C
庫與 Musl C
庫可選焦履,LiteOS-M
內(nèi)核編譯采用 gn
結合 Kconfig
圖形化配置等需求拓劝。
編譯構建
目錄規(guī)劃
本案例在芯片移植架構方面進行了一些改進,以前的芯片適配目錄規(guī)劃為:
device
└── <device_company>
└── <device_name>
這樣會導致嘉裤,小熊派 BearPi-HM Nano
開發(fā)板與潤和的 HiSpark Pegasus
開發(fā)板使用小海思的 hi3861
的 SoC
時郑临,需要在這兩款開發(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)境變量,為編譯做準備笨触。
具體的預編譯適配步驟如下:
- 在
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)
}
- 在
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對應
- 驗證
hb set
配置是否正確捉腥,輸入hb set
能夠顯示如下圖片表示配置正確氓拼。
執(zhí)行 hb set
輸入項目根目錄,并且回車抵碟,hb
命令會遍歷所有 //vendor/<product_company>/<product_name>
目錄下的 config.json
桃漾,給出可選產(chǎn)品編譯選項,config.json
的 product_name
用于顯示產(chǎn)品名拟逮,device_company
和 board
用于關聯(lián)出 //device/board/<device_company>/<board>
目錄撬统,并且匹配 <any_dir_name>/config.gni
文件,如果能夠匹配多個文件唱歧,表示該單板適配了多個內(nèi)核宪摧,那么可以根據(jù) config.json
的 kernel_type
和 kernel_version
來唯一匹配 config.gni
的 kernel_type
和 kernel_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_PATH
、DEVICE_PATH
和 BOARD_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 menuconfig
的 defconfig
保存路徑:
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
中抄瑟,指定了 Board
和 SoC
的編譯入口為 //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)核啟動適配總體思路如下:
- 中斷向量的初始化
os_vector_init
侮措,初始化中斷的處理函數(shù)懈叹。 - 內(nèi)核初始化
osKernelInitialize
。 - 創(chuàng)建線程
board_main
萝毛,進行芯片平臺初始化项阴。 - 內(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
的支持 XIP
的 Nor Flash
漏策,文件系統(tǒng)可以使用 example
掺喻,適配過程中感耙,需要在指定路徑下放置文件系統(tǒng)預置文件即硼,根據(jù)配置可自動生成文件系統(tǒng)鏡像,可以實現(xiàn)自動化生成和打包到燒錄包中屡拨。
- 配置指定目錄放置打包文件系統(tǒng)
config.json
只酥,通過flash_partition_dir
指定目錄:
"flash_partition_dir": "fs" --- 表示在vendor/bestechnic/display_demo/fs目錄下放置文件系統(tǒng)預置文件
- 在指定目錄
vendor/bestechnic/display_demo/fs
下放置兩部分內(nèi)容:
-
wifi_Download_cfg.yaml
:鏡像的燒錄配置文件层皱,可以根據(jù)實際情況調(diào)整分區(qū)赠潦。 -
/data/data
:第一個/data
是掛載的根目錄;第二個data
是根目錄里面的data
目錄草冈,里面可以存放預置文件,或者在第二個data
的同級目錄再創(chuàng)建一個目錄怎棱,打包的時候只認第一個data
掛載根目錄哩俭。
-
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)
- 在
//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ù)的符號传藏,因此需要用到gcc
的wrap
的鏈接選項替換這些函數(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
, snprintf
和 sprintf
禽最。
類似 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
熊昌,spi
,uart
祖屏,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
驅動的源碼適配铃彰。
首先,按照 OpenHarmony
的 HDF
驅動框架加載驅動基本適配框架芯咧,如下:
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.c
和 wifi_hotspot.c
分別適配 wifi_device.h
和 wifi_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_INIT
將 Init
函數(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ā),詳細步驟如下:
- 用
DevEco Studio
編寫 js 應用臀规。 - 使用預覽功能進行預覽滩援,并且得到 js 包:
entry\.preview\intermediates\res\debug\lite\assets\js\default
。 - 將 js 包放到對應的文件系統(tǒng)目錄下塔嬉,文件系統(tǒng)路徑為
vendor/bestechnic/display_demo/fs/data/data/js
玩徊,如下:
├── app.js
├── common
├── i18n
├── manifest.json
└── pages
- 最終編譯生成系統(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
目錄,包含 launcher
和 js app
這兩類應用,應用的函數(shù)調(diào)用流程描述如下:
-
launcher
應用俩檬,通過InstallLauncher
安裝BundleName
為"com.example.launcher"
的native ui
應用萎胰,在AbilityMgrSliteFeature
啟動后會調(diào)用AbilityMgrHandler::StartLauncher()
啟動launcher
應用。 -
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