本文章基于恒玄科技BES2600W
芯片的歐智通 Multi-modal V200Z-R開發板 ,進行輕量帶屏開發板的標準移植,開發了智能開關面板樣例,同時實現了ace_engine_lite
、arkui_ui_lite
、aafwk_lite
、appexecfwk_lite
、HDF
等部件基于OpenHarmony LiteOS-M
內核的適配。移植架構上采用Board
與SoC
分離的方案,工具鏈Newlib C
庫與Musl C
庫可選,LiteOS-M
內核編譯采用gn
結合Kconfig
圖形化配置等需求。
編譯構建
目錄規劃
本案例在芯片移植架構方面進行了一些改進,以前的芯片適配目錄規劃為:
device
└── <device_company>
└── <device_name>
這樣會導致,小熊派BearPi-HM Nano
開發板與潤和的HiSpark Pegasus
開發板使用小海思的hi3861
的SoC
時,需要在這兩款開發板里面都放置一份重復的代碼。為了解決該問題,本案例將單板廠商與SoC
廠商進行分離,可以參考Board和SoC解耦的設計思路,并把芯片適配目錄規劃為:
device
├── board --- 單板廠商目錄
│ └── fnlink --- 單板廠商名字:歐智通
│ └── v200zr --- 單板名:v200zr
└── soc --- SoC廠商目錄
└── bestechnic --- SoC廠商名字:恒玄
└── bes2600 --- SoC Series名:bes2600是一個系列,里面包含bes2600w等SoC名
產品樣例目錄規劃為:
vendor
└── bestechnic --- 開發產品樣例廠商目錄,恒玄開發的帶屏樣例,因此以bestechnic命名
└── display_demo --- 產品名字:以智能開關面板的帶屏顯示樣例
預編譯適配
在進行移植之前,需要進行預編譯適配。
預編譯適配主要使用hb set
命令,設置整個項目的根目錄、單板目錄、產品目錄、單板公司名等環境變量,為編譯做準備。
具體的預編譯適配步驟如下:
- 在
vendor/bestechnic/display_demo
目錄下新增config.json
文件,用于描述這個產品樣例所使用的單板、內核等信息,描述信息可參考如下內容:
{
"product_name": "display_demo", --- 用于hb set進行選擇時,顯示的產品名稱
"type": "mini", --- 構建系統的類型,mini/small/standard
"version": "3.0", --- 構建系統的版本,1.0/2.0/3.0
"device_company": "fnlink", --- 單板廠商名,用于編譯時找到/device/board/fnlink目錄
"board": "v200zr", --- 單板名,用于編譯時找到/device/board/fnlink/v200zr目錄
"kernel_type": "liteos_m", --- 內核類型,因為OpenHarmony支持多內核,一塊單板可能適配了多個內核,所以需要指定某個內核進行編譯
"kernel_version": "3.0.0", --- 內核版本,一塊單板可能適配了多個linux內核版本,所以需要指定某個具體的內核版本進行編譯
"subsystems": [ ] --- 選擇所需要編譯構建的子系統
}
- 在
device/board/fnlink/v200zr/liteos_m
目錄下新增config.gni
文件,用于描述這個產品樣例所使用的單板、內核等信息,描述信息可參考如下內容:
# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
kernel_type = "liteos_m" --- 內核類型,跟config.json中kernel_type對應
# Kernel version.
kernel_version = "3.0.0" --- 內核版本,跟config.json中kernel_version對應
- 驗證
hb set
配置是否正確,輸入hb set
能夠顯示如下圖片表示配置正確。
執行hb set
輸入項目根目錄,并且回車,hb
命令會遍歷所有//vendor/<product_company>/<product_name>
目錄下的config.json
,給出可選產品編譯選項,config.json
的product_name
用于顯示產品名,device_company
和board
用于關聯出//device/board/<device_company>/<board>
目錄,并且匹配<any_dir_name>/config.gni
文件,如果能夠匹配多個文件,表示該單板適配了多個內核,那么可以根據config.json
的kernel_type
和kernel_version
來唯一匹配config.gni
的kernel_type
和kernel_version
,即可確定了需要編譯適配了哪個內核的單板。
過hb env
可以查看選擇出來的預編譯環境變量。
在執行hb build
之前,需要準備好LiteOS-M
內核適配,具體適配步驟請參內核移植。
內核移植
內核移植需要完成LiteOS-M Kconfig
適配、gn
的編譯構建和內核啟動最小適配。
LiteOS-M Kconfig適配
在//kernel/liteos_m
目錄下執行make menuconfig
命令,完成編譯配置選項的選擇。在Makefile
文件中,會將hb env
的結果轉換成環境變量,即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環境變量
在//kernel/liteos_m/Kconfig
文件中使用這些導出的環境變量,Kconfiglib
采用ulfalizer
開發基于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支持多內核設計,Kconfig文件采用liteos_m作為后綴,在進行單板適配過程中,其他內核在適配過程中,可以使用對應的內核名作為后綴名進行擴展。
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后,才會出現如下配置選項
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
配置完成后,還需要根據 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)中,由產品最終定義
endif
……
update_config menuconfig:
$(HIDE)test -f "$(CONFIG)" && cp -v "$(CONFIG)" .config && menuconfig $(args) && savedefconfig --out "$(CONFIG)"
在這個例子中,defconfig
配置路徑為 $(PRODUCT_PATH)/kernel_configs/debug.config
,創建該文件后,內容為空,產品的目錄文件結構如下:
.
└── display_demo
├── config.json
└── kernel_configs
└── debug.config
配置完成后,在 kernel/liteos_m
目錄下執行 make menuconfig
能夠對SoC Series
/SoC
/Board
進行選擇,如下:
結果將自動保存在$(PRODUCT_PATH)/kernel_configs/debug.config
,下次執行make menuconfig
時會導出保存的結果。
gn編譯適配
在上一步Kconfig
的圖形化配置后,將其生成的配置結果可以作為gn
編譯的輸入,以控制不同模塊是否編譯。另外為了解決之前gn
編寫時,隨意include的問題,內核編譯做了模塊化編譯的設計,使得整個編譯邏輯更加清晰,設計思路請參考LiteOS-M內核BUILD.gn編寫指南。
在 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
中,新增內容如下:
if (ohos_kernel_type == "liteos_m") { --- 由于多內核設計,對于LiteOS-M內核適配,需要用宏來隔離
import("http://kernel/liteos_m/liteos.gni") --- 引入內核gn編寫模板
module_name = get_path_info(rebase_path("."), "name") --- 動態獲取當前文件目錄作為模塊名,防止目錄名修改后,這里還需要跟著修改
module_group(module_name) { --- 采用module_group模板
modules = [ --- 添加需要編譯的模塊
]
}
}
同理//device/soc/bestechnic/BUILD.gn
也是一樣。
內核啟動適配
系統啟動流程分為三個階段:
階段名稱 | 分區規劃 | 描述 |
---|---|---|
BOOT1 | [0, 0x10000] | 第一階段啟動,進行固件啟動 |
BOOT2 | [0x2C010000, 0x2C020000] | 第二階段啟動,進行OTA升級啟動 |
RTOS_MAIN | [0x2C080000, 0x2C860000] | 第三階段啟動,進行內核啟動 |
在第三階段內核啟動中,需要適配的文件路徑在 //device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/rtos/liteos/liteos_m/board.c
內核啟動適配總體思路如下:
- 中斷向量的初始化
os_vector_init
,初始化中斷的處理函數。 - 內核初始化
osKernelInitialize
。 - 創建線程
board_main
,進行芯片平臺初始化。 - 內核啟動,開始調度線程
osKernelStart
。
其中,本章節詳細對第3步進行展開,其他幾步為對內核函數調用,不作詳細描述。
第3步中board_main
在啟動OHOS_SystemInit
之前,需要初始化必要的動作,如下:
...
if(!ret) {
...
OhosSystemAdapterHooks(); --- 系統啟動時候設置鉤子,啟動OpenHarmonyOHOS_SystemInit的之前完成打印和驅動的初始化
...
OHOS_SystemInit(); --- 啟動OpenHarmony服務,以及組件初始化
}
....
OhosSystemAdapterHooks
函數在device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c
文件中,如下:
int OhosSystemAdapterHooks(void)
{
init_trace_system(); --- 初始化打印函數
DeviceManagerStart(); --- 調用DeviceManagerStart函數進行HDF驅動初始化,這個過程會調用單板代碼中的驅動配置文件hdf.hcs以及drivers源碼實現
return 0;
}
littlefs文件系統移植
V200Z-R
開發板開發板采用最大32MB
的支持XIP
的Nor Flash
,文件系統可以使用example
,適配過程中,需要在指定路徑下放置文件系統預置文件,根據配置可自動生成文件系統鏡像,可以實現自動化生成和打包到燒錄包中。
- 配置指定目錄放置打包文件系統
config.json
,通過flash_partition_dir
指定目錄:
"flash_partition_dir": "fs" --- 表示在vendor/bestechnic/display_demo/fs目錄下放置文件系統預置文件
- 在指定目錄
vendor/bestechnic/display_demo/fs
下放置兩部分內容:
-
wifi_Download_cfg.yaml
:鏡像的燒錄配置文件,可以根據實際情況調整分區。 -
/data/data
:第一個/data
是掛載的根目錄;第二個data
是根目錄里面的data
目錄,里面可以存放預置文件,或者在第二個data
的同級目錄再創建一個目錄,打包的時候只認第一個data
掛載根目錄。
-
config.json
中根據wifi_Download_cfg.yaml
最后調整結果。
-
fs_src
配置文件系統掛載名字。 -
fs_name
是最后生成文件系統的名字。 -
block_size
配置成4K
對齊,建議不修改。 -
fs_size
是生成文件系統的大小。 -
burn_name
是燒錄bin
名字的大小。 -
enable
表示是否生成這個文件系統
- 在
//device/soc/bestechnic/bes2600/liteos_m/components/hdf_config/hdf.hcs
文件配置文件系統的燒錄的起始地址、文件系統的大小以及讀數據塊的大小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
加載數據,進行讀寫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庫適配
在輕量系統中,C庫適配比較復雜,設計思路請參考LiteOS-M內核支持musl與newlib平滑切換方案,由于我們的工具鏈采用 gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 自帶newlib
的C庫,那么系統移植整體采用newlib
的C庫。那么在內核的make menuconfig
中選擇newlib
,如下圖:
malloc適配
malloc適配參考The Red Hat newlib C Library-malloc。實現malloc適配有以下兩種方法:
實現
_sbrk_r
函數。這種方法中,內存分配函數使用newlib
中的。實現
_malloc_r
,_realloc_r
,_reallocf_r
,_free_r
,_memalign_r
, 和_malloc_usable_size_r
。這種方法中,內存分配函數可以使用內核的。
為了方便地根據業務進行內存分配算法調優和問題定位,在這兩種方法中,本案例選擇后者。
首先,由于newlib
中已經存在這些函數的符號,因此需要用到gcc
的wrap
的鏈接選項替換這些函數符號為內核的實現,內核的實現為 //kernel/liteos_m/kal/libc/newlib/porting/src/malloc.c
。
然后,在//device/board/fnlink/v200zr/liteos_m/config.gni
的新增這些函數的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等適配
參考 https://sourceware.org/newlib/libc.html#vfprintf ,實現 vprintf
, vfprintf
, printf
, snprintf
和sprintf
。
類似malloc
適配,首先要提供這些函數的實現,//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/printf.c
,本案例直接采用開源協議友好的實現。與malloc
適配不同的是,這個函數由芯片原廠提供。因為就打印來說,根據項目的需要,實現可大可小,內核不方便提供統一的實現。
然后,在//device/board/fnlink/v200zr/liteos_m/config.gni
的新增這些函數的wrap鏈接選項。
board_ld_flags += [
"-Wl,--wrap=printf",
"-Wl,--wrap=sprintf",
"-Wl,--wrap=snprintf",
"-Wl,--wrap=vsnprintf",
"-Wl,--wrap=vprintf",
]
open等適配
這部分實現由內核統一實現,芯片適配無須關注,內核文件//kernel/liteos_m/kal/libc/newlib/porting/src/fs.c
,適配了newlib
的_read
、_write
等函數,如下:
……
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);
}
……
板級系統移植
驅動移植
SoC芯片平臺HDF驅動移植
驅動適配相關文件放置在drivers/adapter/platform
中,對應有gpio
,i2c
,pwm
,spi
,uart
,watchdog
,都是通過HDF
機制加載,本章節以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
參數進行初始化,如下:
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節點變量就可以獲取具體gpio配置
if (gpioCntlr == NULL) {
...
編碼規范和設計思想見bes 驅動適配PR的評論。
Board外設器件HDF驅動移植
Board
外設器件表示通過SoC
平臺總線連接的外設器件,在本案例中,顯示屏屬于外設器件,其驅動適配放在//device/board/fnlink/drivers/liteos_m
目錄中。
顯示驅動適配
同SoC
驅動適配,在//device/board/fnlink/drivers/liteos_m/display/BUILD.gn
文件中,根據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
文件中,根據驅動框架加載顯示驅動,如下:
static struct HdfDriverEntry g_ZZW395DriverEntry = {
.moduleVersion = 1,
.moduleName = "HDF_PANEL_ZZW395",
.Bind = PanelDriverBind,
.Init = PanelDriverInit,
.Release = PanelDriverRelease,
};
HDF_INIT(g_ZZW395DriverEntry);
其中的驅動參數根據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子系統適配
OpenHarmony
子系統適配一般包含兩部分:
- 在
config.json
中增加對應子系統和部件,這樣編譯系統會將該部件納入編譯目標中。 - 針對該部件的
HAL
層接口進行硬件適配,或者可選的軟件功能適配。
分布式軟總線子系統適配
wifi_lite部件適配
首先,在config.json
文件中,增加communication
子系統的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的具體實現,所以wifi模塊暴露出適配的目錄路徑提供給硬件廠商來適配,廠商提供wifi協議棧源碼實現。
}
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熱點的函數,對wifi_device.h中Scan函數的適配實現
{
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信號熱點函數,對wifi_hotspot.h中GetSignalLevel函數的適配實現。
{
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網卡的初始化適配
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
網卡初始化的適配,如下:
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
路徑,該路徑下的內容為:
.
├── feature_config --- 軟總線功能特性配置,例如是否開啟自發現功能等
│ └── mini
│ └── config.gni
└── spec_config --- 軟總線規格特性配置,例如設置軟總線日志級別設置
├── softbus_config_adapter.c
├── softbus_config_adapter.h
└── softbus_config_type.h
在config.gni
文件中規定了以下配置項:
配置項 | 描述 |
---|---|
dsoftbus_feature_disc_ble | 是否開啟BLE發現功能 |
dsoftbus_feature_disc_coap | 是否開啟COAP發現功能 |
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
文件中規定了以下配置項:
配置項 | 描述 |
---|---|
SOFTBUS_INT_MAX_BYTES_LENGTH | SendBytes發送最大Bytes長度 |
SOFTBUS_INT_MAX_MESSAGE_LENGTH | SendMessage發送最大消息的長度 |
SOFTBUS_INT_CONN_BR_MAX_DATA_LENGTH | 藍牙最大接收數據量 |
SOFTBUS_INT_CONN_RFCOM_SEND_MAX_LEN | 藍牙最大接收數據量 |
SOFTBUS_INT_ADAPTER_LOG_LEVEL | 日志級別設置 |
SOFTBUS_STR_STORAGE_DIRECTORY | 存儲目錄設置 |
因為軟總線配置了后,不會默認啟動,所以需要在通過啟動框架調用InitSoftBusServer
函數,如下:
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
部件需要通過啟動框架調用StartDBinderService
函數,由于該函數正常運行依賴主機已經獲取IP
地址,因此在LWIP
協議棧注冊IP
地址變化事件的回調函數中調用該函數,如下:
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);
啟動恢復子系統適配
啟動恢復子系統適配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) | 標識核心系統服務的初始化啟動入口 |
SYS_FEATURE_INIT(func) | 標識核心系統功能的初始化啟動入口 |
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
函數符號灌段到__zinitcall_sys_service_start
和__zinitcall_sys_service_end
中,由于Init
函數是沒有顯式調用它,所以需要將它強制鏈接到最終的鏡像。如下:
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
部件時,系統參數會最終寫到文件中進行持久化保存。在輕量系統中,文件操作相關接口有POSIX
接口與HalFiles
接口這兩套實現。
因為對接內核的文件系統,采用POSIX
相關的接口,所以features
字段中需要增加enable_ohos_startup_syspara_lite_use_posix_file_api = true
。
如果對接HalFiles
相關的接口實現的,則無須修改。
在適配GetSerial
接口時,開發板不像產線生產過程那樣,會寫入一個具體的Serial Number
,因而需要確定一個數據對開發板進行唯一標識。本案例采用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; --- 將數值0轉為char的'0'
} else {
return hex + CHAR_CAPITAL_OFFSET; --- 將數值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) { --- 只有第一次調用時,才去獲取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子系統適配
進行DFX
子系統適配需要添加hilog_lite
部件,直接在config.json
文件配置即可。
{
"subsystem": "hiviewdfx",
"components": [
{
"component": "hilog_lite",
"optional": "true"
}
]
},
配置完成之后,在//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c
中注冊日志輸出實現函數。
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);
系統服務管理子系統適配
進行系統服務管理子系統適配需要添加samgr_lite
部件,直接在config.json
配置即可。
{
"subsystem": "systemabilitymgr",
"components": [
{
"component": "samgr_lite",
"features": [
"config_ohos_systemabilitymgr_samgr_lite_shared_task_size = 4096"
]
}
]
},
在輕量系統中,samgr_lite
配置的共享任務棧大小默認為0x800
。當函數調用棧較大時,會出現棧溢出的問題。在本次適配過程中,將其調整為0x1000
。
安全子系統適配
進行安全子系統適配需要添加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
進行硬件隨機數等適配。
deviceauth_lite
部件適配時,deviceauth_storage_path
配置選項用于指定存放設備認證信息的路徑,deviceauth_hichain_thread_stack_size
用于指定線程棧大小。
媒體子系統適配
進行媒體子系統適配需要添加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棧大小設置 |
公共基礎庫子系統適配
進行公共基礎庫子系統適配需要添加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
部件時,鍵值對會寫到文件中。在輕量系統中,文件操作相關接口有POSIX
接口與HalFiles
接口這兩套實現。因為對接內核的文件系統,采用POSIX
相關的接口,所以features
需要增加enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true
。如果對接HalFiles
相關的接口實現的,則無須修改。
圖形子系統適配
進行圖形子系統適配需要添加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
:初始化字體引擎,執行渲染任務等。
圖形子系統層次:
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開發框架子系統適配
進行ACE
開發框架子系統適配需要添加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語言進行開發,詳細步驟如下:
- 用
DevEco Studio
編寫js應用,參考輕量級智能穿戴開發。 - 使用預覽功能進行預覽,并且得到js包:
entry\.preview\intermediates\res\debug\lite\assets\js\default
。 - 將js包放到對應的文件系統目錄下,文件系統路徑為
vendor/bestechnic/display_demo/fs/data/data/js
,如下:
├── app.js
├── common
├── i18n
├── manifest.json
└── pages
- 最終編譯生成系統鏡像,燒錄到單板后,系統會從
app.js
加載啟動ace
的應用。
元能力子系統適配
進行元能力子系統適配需要添加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
這兩類應用,應用的函數調用流程描述如下:
launcher
應用,通過InstallLauncher
安裝BundleName
為"com.example.launcher"
的native ui
應用,在AbilityMgrSliteFeature
啟動后會調用AbilityMgrHandler::StartLauncher()
啟動launcher
應用。StartJSApp
應用,通過StartAbility
啟動任意Want
,通過將want data
傳遞JS_APP_PATH
,
SetWantData(&want, JS_APP_PATH, strlen(JS_APP_PATH) + 1)
。
包管理子系統適配
進行包管理子系統適配需要添加appexecfwk_lite
部件,直接在config.json
配置即可。
{
"subsystem": "appexecfwk",
"components": [
{
"component": "appexecfwk_lite"
}
]
},
兼容性認證
產品兼容性規范
產品兼容性規范文檔請參考產品兼容性SIG介紹。
XTS用例
XTS
測試參考資料見xts參考資料,進行XTS
子系統適配需要添加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
是配置掛載文件系統根目錄的名字。 -
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
兼容性測試網站進行認證,作為sig
倉庫轉正到master
倉庫的必要條件。詳細步驟如下:
步驟1:將XTS
測試報告壓縮成zip
文件。
步驟2:生成測試報告的SHA
校驗碼。本案例是將zip
文件傳到在線生成hash
的網站生成SHA
校驗碼。
步驟3:進入OpenHarmony
兼容性測試網站上傳報告。
- 其中
API Level
填寫報告中的"sdkApiLevel"
字段 -
OS
版本號填寫報告中的"OS Version"
字段。
todo
后續會補充以下方面的移植:
- 藍牙
-
bms
包安裝 - 驗證運行
JS
的bytecode
- 分布式能力:
dms
、dm
- 分布式音樂播放器樣例
porting-bes2600w-on-minisystem-display-demo.md
寫在最后
如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
- 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
- 關注小編,同時可以期待后續文章ing??,不定期分享原創知識。
- 想要獲取更多完整鴻蒙最新學習知識點,請移步前往小編:
https://gitee.com/MNxiaona/733GH/blob/master/jianshu