本稿は、ベステックテクノロジーの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シリーズ名:bes2600シリーズにはbes2600wなどのSoCが含まれる
製品サンプルのディレクトリ構成は以下の通りです:
vendor
└── 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は複数カーネルをサポートし、1つの単板が複数カーネルに適合している可能性があるため、コンパイルする特定のカーネルを指定
"kernel_version": "3.0.0", --- カーネルバージョン:1つの単板が複数の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を実行し、プロジェクトルートディレクトリを入力してEnterキーを押すと、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でも使用できるため、ここでは*ですべての拡張ボードを一致させます。また、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シリーズ選択リストを提供
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 --- ベステックチップメーカーのbes2600w SoCシリーズ設定
│ ├── Kconfig.liteos_m.defconfig.series --- ベステックチップメーカーのbes2600デフォルト設定
│ ├── Kconfig.liteos_m.series --- ベステックチップメーカーのbes2600 SoCシリーズ設定
│ └── Kconfig.liteos_m.soc --- ベステックチップメーカーのbes2600 SoC設定
├── Kconfig.liteos_m.defconfig --- ベステックチップメーカーのSoCデフォルト設定
├── Kconfig.liteos_m.series --- ベステックチップメーカーのSoCシリーズ設定
└── Kconfig.liteos_m.soc --- ベステックチップメーカーのSoC設定
bes2600/Kconfig.liteos_m.seriesでは、bes2600 SoCシリーズとそのチップアーキテクチャ情報などを設定する必要があります。例えば以下の通りです:
config SOC_SERIES_BES2600 --- bes2600 SoCシリーズオプションを提供
bool "Bestechnic 2600 Series"
select ARM --- bes2600を選択すると、デフォルトでARMアーキテクチャが選択されます
select SOC_COMPANY_BESTECHNIC --- bes2600を選択すると、デフォルトでベステックチップ会社が選択され、ドライバはこのマクロ設定に依存し、対応するメーカーのドライバを選択してコンパイルします
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シリーズが選択された場合にのみ、以下の設定オプションが表示されます
config SOC_BES2600W --- bes2600w SoC設定オプションを追加
bool "SoC BES2600w"
endchoice
bes2600/Kconfig.liteos_m.defconfig.seriesでは、bes2600 SoC series選択後のデフォルト設定を提供する必要があります。例えば以下の通りです:
if SOC_SERIES_BES2600 --- bes2600シリーズが選択された場合にのみ、以下のデフォルト設定オプションが追加されます
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 += [ "//device/board/$device_company" ]
deps += [ "//device/soc/$LOSCFG_SOC_COMPANY" ]
//device/board/fnlink/BUILD.gnでは、以下の内容を新規追加します:
if (ohos_kernel_type == "liteos_m") { --- 多カーネル設計のため、LiteOS-Mカーネル適合ではマクロで分離する必要があります
import("//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も同じです。
カーネル起動適合
システム起動プロセスは3つの段階に分けられます:
| 段階名 | パーティション計画 | 説明 |
|---|---|---|
| BOOT1 | \[0, 0x10000\] | 第1段階起動:ファームウェア起動 |
| BOOT2 | \[0x2C010000, 0x2C020000\] | 第2段階起動:OTAアップグレード起動 |
| RTOS\_MAIN | \[0x2C080000, 0x2C860000\] | 第3段階起動:カーネル起動 |
第3段階のカーネル起動では、適合が必要なファイルパスは//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(); --- システム起動時にフックを設定し、OpenHarmony OHOS_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に以下の2つの内容を配置します:
wifi_Download_cfg.yaml:イメージの焼き込み設定ファイル、実際の状況に応じてパーティションを調整できます。/data/data:最初の/dataはマウントするルートディレクトリです。2番目のdataはルートディレクトリ内のdataディレクトリで、事前設定ファイルを格納したり、2番目の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適合には以下の2つの方法があります:
_sbrk_r関数を実装する方法。この方法では、メモリ割り当て関数はnewlibのものを使用します。_malloc_r,_realloc_r,_reallocf_r,_free_r,_memalign_r, および_malloc_usable_size_rを実装する方法。この方法では、メモリ割り当て関数はカーネルのものを使用できます。
ビジネスに基づいたメモリ割り当てアルゴリズムの最適化と問題特定を容易にするため、この2つの方法の中で、本ケースでは後者を選択します。
まず、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) {
...
コーディング規約と設計思想はベステックドライバ適合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 = [
"//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サブシステム適合には通常、2つの部分が含まれます:
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": [
"//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が設定されているため、コンパイル機能があります。カーネルコンポーネントでlwipコンパイルのディレクトリを指定できます。以下の通りです:
{
"subsystem": "kernel",
"components": [
{
"component": "liteos_m",
"features": [
"ohos_kernel_liteos_m_lwip_path = \"//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("//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 = \"//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送信最大バイト長 |
| SOFTBUS\_INT\_MAX\_MESSAGE\_LENGTH | SendMessage送信最大メッセージ長 |
| SOFTBUS\_INT\_CONN\_BR\_MAX\_DATA\_LENGTH | Bluetooth最大受信データ量 |
| SOFTBUS\_INT\_CONN\_RFCOM\_SEND\_MAX\_LEN | Bluetooth最大受信データ量 |
| 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の2つのコンポーネントがあります。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インターフェースの2つの実装があります。
カーネルのファイルシステムに接続するため、POSIX関連インターフェースを使用するため、featuresフィールドにenable_ohos_startup_syspara_lite_use_posix_file_api = trueを追加する必要があります。
HalFiles関連インターフェースの実装に接続する場合は、変更する必要はありません。
GetSerialインターフェースを適合する際、開発ボードは量産プロセスのように具体的なシリアル番号が書き込まれていないため、開発ボードを一意に識別するデータを特定する必要があります。本ケースでは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]; --- 最後の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 = \"//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インターフェースの2つの実装があります。カーネルのファイルシステムに接続するため、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(); --- ネイティブuiデモ
#elif defined(ABILITY_TEST)
StartJSApp(); --- jsデモ
#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の2種類のアプリケーションを含みます。アプリケーションの関数呼び出しフローは以下のように説明します:
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"フィールドを記入
今後の計画
今後、以下の方面の移植を補充予定です:
- Bluetooth
bmsパッケージインストールJSのbytecode実行の検証- 分散能力:
dms、dm - 分散音楽プレーヤーサンプル