1# Mini-System Devices with Screens – Bestechnic SoC Porting Case 2 3This document exemplifies the porting procedure for a development board on a mini-system device with a screen – an intelligent switch panel. It uses the BES multi-modal V200Z-R development board powered by the Bestechnic BES2600W SoC as an example. Components such as `ace_engine_lite`, `graphic_ui`, `aafwk_lite`, `appexecfwk_lite`, and `HDF` are adapted based on the OpenHarmony LiteOS-M kernel. This example uses the board-SoC separation solution as the porting architecture, the Newlib C or Musl C library as the toolchain, and GN and Kconfig graphical configuration for LiteOS-M kernel compilation. 4 5## Compilation and Building 6 7### Directory Planning 8 9This example uses an improved SoC porting architecture. The original SoC adaptation directory is as follows: 10 11``` 12device 13└── <device_company> 14 └── <device_name> 15``` 16 17This adaptation directory has a downside: To use the Hi3861 SoC on the BearPi-HM Nano or HiSpark Pegasus development board, you need to place a copy of the code in the directory of both development boards. To solve this problem, the board vendor is decoupled from the SoC vendor in this example, by following the board-SoC decoupling design ideas. The SoC adaptation directory used in this example is as follows: 18 19``` 20device 21├── board --- Board vendor directory 22│ └── fnlink --- Board vendor name: Fn-Link 23│ └── v200zr --- Board name: v200zr 24└── soc --- SoC vendor directory 25 └── bestechnic --- SoC vendor: Bestechnic 26 └── bes2600 --- SoC Series: The bes2600 series includes bes2600w. 27``` 28 29The planned product demo directory is as follows: 30 31``` 32vendor 33└── bestechnic --- Vendor of the product demo. 34 └── display_demo --- Product demo name. 35``` 36 37### Precompilation Adaptation 38 39Before porting, you need to perform precompilation adaptation. 40 41To do so, use the `hb set` command to set environment variables such as the root directory, board directory, product directory, and board company name of the entire project. 42 43The specific procedure is as follows: 44 451. Add the `config.json` file to the `vendor/bestechnic/display_demo` directory to describe the board and kernel information used by the product demo. The following is an example of the description: 46 47``` 48{ 49 "product_name": "display_demo", --- Product name to display in the hb set drop-down list. 50 Type of the "type": "mini", --- Build system type, which can mini, small, or standard. 51 Version of the "version": "3.0", --- Build system version, which can be 1.0, 2.0, or 3.0. 52 "device_company": "fnlink", --- Board vendor name, which is used to find the /device/board/fnlink directory during compilation. 53 "board": "v200zr", --- Board name, which is used to find the /device/board/fnlink/v200zr directory during compilation. 54 "kernel_type": "liteos_m", --- Kernel type. OpenHarmony supports multiple kernels, and one board may be adapted to multiple kernels. Therefore, you need to specify a kernel for compilation. 55 "kernel_version": "3.0.0", --- Kernel version. A board may be adapted to multiple Linux kernel versions. Therefore, you need to specify a kernel version for compilation. 56 "subsystems": [ ] --- Subsystem to be compiled and built. 57} 58``` 59 602. Add the `config.gni` file to the `device/board/fnlink/v200zr/liteos_m` directory to describe the board and kernel used in the product demo. The following is an example of the description: 61 62``` 63# Kernel type, e.g. "linux", "liteos_a", "liteos_m". 64kernel_type = "liteos_m" --- Kernel type, which corresponds to kernel_type in the config.json file. 65 66# Kernel version. 67kernel_version = "3.0.0" --- Kernel version, which corresponds to kernel_version in the config.json file. 68``` 69 703. Verify the `hb set` configuration: 71 72 Run the `hb set` command, enter the project root directory, and press `Enter`. The `hb` command traverses all `config.json` files in the `//vendor/<product_company>/<product_name>` directory and provides product compilation options. In the `config.json` file, `product_name` indicates the product name, `device_company` and `board` are used to locate the `//device/board/<device_company>/<board>` directory and find the matching `<any_dir_name>/config.gni` file. If multiple file matches are found, it indicates that the board has been adapted to multiple kernels. In this case, `kernel_type` and `kernel_version` in the `config.json` file can be used to uniquely match the `config.gni` file and thereby determine the board with which kernel needs to be compiled and adapted. If the information shown below is displayed, the `hb set` configuration is correct. 73 74 ![hb set](figures/bes2600_hb_set.png) 75 76 You can run the `hb env` command to view the selected precompilation environment variables. 77 78![hb env](figures/bes2600_hb_env.png) 79 80Before running the `hb build` command, complete the LiteOS-M kernel adaptation. For details, see [Kernel Porting](https://gitee.com/openharmony/docs/blob/master/en/device-dev/porting/porting-bes2600w-on-minisystem-display-demo.md#%E5%86%85%E6%A0%B8%E7%A7%BB%E6%A4%8D). 81 82## Kernel Porting 83 84To port the kernel, you need to complete the LiteOS-M Kconfig adaptation, GN compilation and building, and minimum adaptation for kernel startup. 85 86### LiteOS-M Kconfig Adaptation 87 88Run the `make menuconfig` command in the `//kernel/liteos_m` directory to select compilation configuration options. In the `Makefile` file, the `hb env` result is converted into environment variables, that is, `PRODUCT_PATH`, `DEVICE_PATH`, and `BOARD_COMPANY`. The sample code is as follows: 89 90``` 91$(foreach line,$(shell hb env | sed 's/\[OHOS INFO\]/ohos/g;s/ /_/g;s/:_/=/g' || true),$(eval $(line))) 92ifneq ($(ohos_kernel),liteos_m) 93$(error The selected product ($(ohos_product)) is not a liteos_m kernel type product) 94endif 95--- Convert each line of hb env to a variable. For example, convert [OHOS INFO] device company: fnlink to ohos_device_company=fnlink. 96 97... 98 99ifeq ($(BOARD_COMPANY),) 100BOARD_COMPANY:=$(ohos_device_company) 101endif 102... 103export BOARD_COMPANY 104--- Convert ohos_device_company to the BOARD_COMPANY environment variable. 105``` 106 107Use the exported environment variables in the `//kernel/liteos_m/Kconfig` file. `Kconfiglib` uses `ulfalizer` to develop the Python-based version. In the [source code](https://github.com/ulfalizer/Kconfiglib), as described in [function description](https://github.com/zephyrproject-rtos/zephyr/blob/main/scripts/kconfig/kconfiglib.py), the keyword `orsource` is used. In this keyword, `o` indicates `optional`, that is, the file is optional. `r` indicates `relative`, that is, the path of the file relative to the current file. 108 109``` 110config SOC_COMPANY 111 string "SoC company name to locate soc build path" 112 help 113 This option specifies the SoC company name, used to locate the build path for soc. This option is set by the 114 SoC's Kconfig file, and should be exactly the same with SoC company path, and the user should generally avoid 115 modifying it via the menu configuration. 116 117orsource "../../device/board/*/Kconfig.liteos_m.shields" --- Load the configurations of all extension boards. To allow the extension boards provided by board vendor A to be used by board vendor B, the asterisk (*) instead of BOARD_COMPANY is used. As OpenHarmony supports the multi-kernel design, the Kconfig file uses liteos_m as the suffix. During board adaptation, the actual kernel name can be used as the suffix for extension during kernel adaptation. 118 119orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.defconfig.boards" --- Load all predefined board configurations of BOARD_COMPANY. 120 121choice 122 prompt "Board Selection" 123 124The orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.boards" --- Provide a list of available boards. 125 126endchoice 127 128orsource "../../device/soc/*/Kconfig.liteos_m.defconfig" --- Load the default configuration definitions of all SoCs. 129 130choice 131 prompt "SoC Series Selection" 132 133orsource "../../device/soc/*/Kconfig.liteos_m.series" --- Provide a list of available SoC series. 134 135endchoice 136 137orsource "../../device/soc/*/Kconfig.liteos_m.soc" --- Load all SoC configurations. 138``` 139 140According to the `//kernel/liteos_m/Kconfig` file, the following `Kconfig` files need to be added to the `//device/board/fnlink` directory for adaptation: 141 142``` 143. 144├── v200zr --- Configuration of the v200zr 145│ ├── Kconfig.liteos_m.board --- Configuration options of the v200zr board 146│ ├── Kconfig.liteos_m.defconfig.board --- Default configuration items of the v200zr board 147│ └── liteos_m 148│ └── config.gni 149├── Kconfig.liteos_m.boards --- Board configuration of Fn-Link 150├── Kconfig.liteos_m.defconfig.boards --- Default board configuration of Fn-Link 151├── Kconfig.liteos_m.shields --- Extension board configuration of Fn-Link 152└── shields --- Extension board directory of Fn-Link 153 ├── v200zr-t0 --- Expansion board v200zr-t0 of Fn-Link 154 │ ├── Kconfig.liteos_m.defconfig.shield --- Default configuration of the expansion board v200zr-t0 155 │ └── Kconfig.liteos_m.shield --- Configuration of the expansion board v200zr-t0 156 ├── v200zr-t1 157 │ ├── Kconfig.liteos_m.defconfig.shield 158 │ └── Kconfig.liteos_m.shield 159 └── Kconfig.liteos_m.shields 160``` 161 162In `v200zr/Kconfig.liteos_m.board`, you need to set the board configuration options and the dependent `SoC` as follows: 163 164``` 165config BOARD_v200zr 166 bool "select board v200zr" 167 depends on SOC_BES2600W --- The v200zr board uses the bes2600w SoC. Therefore, the v200zr board configuration options are available only when the bes2600w SoC is selected. 168``` 169 170In `v200zr/Kconfig.liteos_m.defconfig.board`, the default name of `BOARD` is defined as `"v200zr"`. 171 172``` 173if BOARD_v200zr 174config BOARD 175 string --- No content is defined for string. Therefore, it is not visible to users. 176 default "v200zr" 177 178endif # BOARD_v200zr 179``` 180 181According to the `//kernel/liteos_m/Kconfig` file, the following `Kconfig` files need to be added to the `//device/soc/bestechnic` directory for adaptation: 182 183``` 184. 185├── bes2600 --- bes2600 SoC series 186│ ├── Kconfig.liteos_m.defconfig.bes2600w --- Configuration of the bes2600w SoC series provided by Bestechnic 187│ ├── Kconfig.liteos_m.defconfig.series --- Default configuration of the bes2600 provided by Bestechnic 188│ ├── Kconfig.liteos_m.series --- Configuration of the bes2600 SoC series provided by Bestechnic 189│ └── Kconfig.liteos_m.soc --- Configuration of the bes2600 SoC provided by Bestechnic 190├── Kconfig.liteos_m.defconfig --- Default SoC configuration of Bestechnic 191├── Kconfig.liteos_m.series --- Configuration of the SoC series provided by Bestechnic 192└── Kconfig.liteos_m.soc --- Configuration of the SoC provided by Bestechnic 193``` 194 195In the `bes2600/Kconfig.liteos_m.series` file, configure the `bes2600 SoC series` and SoC architecture as follows: 196 197``` 198config SOC_SERIES_BES2600 --- bes2600 SoC series configuration options 199 bool "Bestechnic 2600 Series" 200 select ARM --- When bes2600 is selected, the ARM architecture is selected by default. 201 select SOC_COMPANY_BESTECHNIC --- When bes2600 is selected, bestechnic is selected by default. The driver depends on the macro configuration. You can select the configuration to compile the driver of the corresponding vendor. 202 select CPU_CORTEX_M33 --- When bes2600 is selected, cortex-m33 CPU is selected by default. 203 help 204 Enable support for Bestechnic 2600 series 205``` 206 207In the `bes2600/Kconfig.liteos_m.soc` file, provide the number of specific SoCs under the `bes2600 SoC series` as follows: 208 209``` 210choice 211 prompt "Bestechnic 2600 series SoC" 212 depends on SOC_SERIES_BES2600 --- The following configuration options are displayed only when bes2600 Series is selected: 213 214config SOC_BES2600W --- Add the bes2600w SoC configuration option. 215 bool "SoC BES2600w" 216 217endchoice 218``` 219 220In the `bes2600/Kconfig.liteos_m.defconfig.series` file, provide the following configuration that is used by default when the bes2600 SoC series is selected: 221 222``` 223if SOC_SERIES_BES2600 --- The following default configuration options are added only when the bes2600 series is selected: 224 225rsource "Kconfig.liteos_m.defconfig.bes2600w" --- Add the default configuration that is used by default when bes2600 SoC series is selected. 226 227config SOC_SERIES --- Add the configuration that is used by default when SOC_SERIES is selected: 228 string 229 default "bes2600" 230 231endif 232``` 233 234When the configuration is complete, set the `defconfig` storage path of `make menuconfig` based on the `kernel/liteos_m/Makefile` file. 235 236``` 237ifeq ($(TEE:1=y),y) 238tee = _tee 239endif 240ifeq ($(RELEASE:1=y),y) 241CONFIG ?= $(PRODUCT_PATH)/kernel_configs/release$(tee).config 242else 243CONFIG ?= $(PRODUCT_PATH)/kernel_configs/debug$(tee).config --- The configuration file is saved in $(CONFIG) and is defined by the product. 244endif 245 246... 247 248update_config menuconfig: 249 $(HIDE)test -f "$(CONFIG)" && cp -v "$(CONFIG)" .config && menuconfig $(args) && savedefconfig --out "$(CONFIG)" 250``` 251 252In this example, the configuration file of `defconfig` is saved in `$(PRODUCT_PATH)/kernel_configs/debug.config`. It is empty by default upon creation. The directory and file structure of the product is as follows: 253 254``` 255. 256└── display_demo 257 ├── config.json 258 └── kernel_configs 259 └── debug.config 260``` 261 262When the configuration is complete, run the `make menuconfig` command in the `kernel/liteos_m` directory to select `SoC Series`/`SoC`/`Board`. 263 264![board make menuconfig](figures/bes2600_board_make_menuconfig.png) 265 266The result is automatically saved in `$(PRODUCT_PATH)/kernel_configs/debug.config` and will be exported when `make menuconfig` is executed. 267 268### GN Build Adaptation 269 270The graphical configuration result of `Kconfig` generated in the previous step can be used as the input of GN build to determine whether to build different modules. In addition, to solve the problem of arbitrary use of `include` during GN build, modular compilation is used for kernel compilation, streamlining the entire compilation logic. For details, see *LiteOS-M Kernel BUILD.gn Compilation Guide*. 271 272In the `kernel/liteos_m/BUILD.gn` file, the compilation entrances of `Board` and `SoC` are specified as `//device/board/fnlink` and `//device/soc/bestechnic`. 273 274``` 275deps += [ "//device/board/$device_company" ] 276deps += [ "//device/soc/$LOSCFG_SOC_COMPANY" ] 277``` 278 279Add the following content to `//device/board/fnlink/BUILD.gn`: 280 281``` 282if (ohos_kernel_type == "liteos_m") { --- In the multi-kernel design, macros need to be used to isolate the adapted LiteOS-M kernel. 283 import("//kernel/liteos_m/liteos.gni") --- Import the kernel GN template. 284 module_name = get_path_info(rebase_path("."), "name") --- Dynamically obtain the current directory and use it as the module name, eliminating the need for manual synchronization between the directory and module name. 285 module_group(module_name) { --- Use the module_group template. 286 modules = [ --- Add the modules to be built. 287 ] 288 } 289} 290``` 291 292Modify the `//device/soc/bestechnic/BUILD.gn` file in a similar manner. 293 294### Kernel Boot Adaptation 295 296The system boot process consists of three phases: 297 298| Phase | Partitioning Planning | Description | 299| --------- | ------------------------ | ----------------------------- | 300| BOOT1 | [0, 0x10000] | The firmware is started. | 301| BOOT2 | [0x2C010000, 0x2C020000] | The OTA update starts.| 302| RTOS_MAIN | [0x2C080000, 0x2C860000] | The kernel is started. | 303 304In the third phase where the kernel is started, the file to be adapted is saved in `//device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/rtos/liteos/liteos_m/board.c`. 305 306The general idea of kernel boot adaptation is as follows: 307 3081. `os_vector_init` is used to initialize interrupt vectors and interrupt processing functions. 3092. `osKernelInitialize` is used to initialize the kernel. 3103. The `board_main` thread is created to initialize the chip platform. 3114. The kernel starts up and schedules the `osKernelStart` thread. 312 313This section describes step 3 in detail. Other steps involve invoking of kernel functions and are not described here. 314 315In step 3, before starting `OHOS_SystemInit`, `board_main` needs to complete the necessary actions as follows: 316 317``` 318... 319 if(!ret) { 320 ... 321 OhosSystemAdapterHooks(); --- Configure the hook during system boot and complete the printing and driver initialization before OHOS_SystemInit is started. 322 ... 323 OHOS_SystemInit(); --- Start the OpenHarmony service and initialize components. 324 } 325.... 326``` 327 328The `OhosSystemAdapterHooks` function is in the `device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c` file, as shown below: 329 330``` 331int OhosSystemAdapterHooks(void) 332{ 333 init_trace_system(); --- Initialize the printing function. 334 DeviceManagerStart(); --- Call the DeviceManagerStart function to initialize the HDF driver. This process is implemented by calling the driver configuration file hdf.hcs in the board code and implementing the drivers source code. 335 return 0; 336} 337 338``` 339 340### littlefs File System Porting 341 342 The `V200Z-R` development board uses the `Nor Flash` that supports `XIP` and has a maximum size of `32 MB`. The `example` file system can be used. During the adaptation, place the file system configuration file in the specified path. The file system image is then automatically generated based on the configuration and packaged into the burning package. 343 3441. Specify the directory for storing the file system `config.json` by using `flash_partition_dir`. 345 346``` 347 "flash_partition_dir": "fs" --- Store the file system configuration file in the vendor/bestechnic/display_demo/fs directory. 348``` 349 3502. Place the following items in the `vendor/bestechnic/display_demo/fs` directory: 351 352 - `wifi_Download_cfg.yaml`: configuration file for image burning. The partitions can be adjusted as required. 353 - `/data/data`: The first /`data` is the root directory to mount. The second `data` is the `data` directory in the root directory. You can place the configuration file in the second `data` directory or in any directory at the same level. During packaging, the whole root directory is packaged. 354 3553. Set the following items in the `config.json` file based on the `wifi_Download_cfg.yaml` file: 356 357 - `fs_src`: name under which the file system is mounted. 358 - `fs_name`: name of the generated file system. 359 - `block_size`: size of the read data block. Set it to `4K` alignment and do not change the value. 360 - `fs_size`: size of the generated file system. 361 - `burn_name`: size of the burnt `bin` name. 362 - `enable`: whether to generate the file system. 363 3644. In the `//device/soc/bestechnic/bes2600/liteos_m/components/hdf_config/hdf.hcs` file, configure the start address for burning the file system, size of the file system, and size of the read data block (`block_size`). The reference configuration is as follows: 365 366``` 367 misc { 368 fs_config { 369 example_config { 370 match_attr = "littlefs_config"; 371 mount_points = ["/data"]; 372 partitions = [10]; 373 block_size = [4096]; 374 block_count = [1024]; 375 } 376 } 377 storage_config { 378 flash_config { 379 match_attr = "flash_config"; 380 partitions = [10]; 381 owner = [0]; 382 description = ["littlefs"]; 383 start_addr = [0xB60000]; 384 length = [0x400000]; 385 options = [3]; 386 } 387 } 388 } 389``` 390 391In `device/soc/bestechnic/bes2600/liteos_m/components/fs/fs_init.c`, load data through `hdf` and read and write to `flash` as follows: 392 393``` 394static int32_t FsDriverInit(struct HdfDeviceObject *object) 395{ 396 if (object == NULL) { 397 return HDF_FAILURE; 398 } 399 if (object->property) { 400 if (FsGetResource(fs, object->property) != HDF_SUCCESS) { 401 HDF_LOGE("%s: FsGetResource failed", __func__); 402 return HDF_FAILURE; 403 } 404 } 405 for (int i = 0; i < sizeof(fs) / sizeof(fs[0]); i++) { 406 if (fs[i].mount_point == NULL) 407 continue; 408 409 fs[i].lfs_cfg.read = littlefs_block_read; 410 fs[i].lfs_cfg.prog = littlefs_block_write; 411 fs[i].lfs_cfg.erase = littlefs_block_erase; 412 fs[i].lfs_cfg.sync = littlefs_block_sync; 413 414 fs[i].lfs_cfg.read_size = 256; 415 fs[i].lfs_cfg.prog_size = 256; 416 fs[i].lfs_cfg.cache_size = 256; 417 fs[i].lfs_cfg.lookahead_size = 16; 418 fs[i].lfs_cfg.block_cycles = 1000; 419 420 int ret = mount(NULL, fs[i].mount_point, "littlefs", 0, &fs[i].lfs_cfg); 421 HDF_LOGI("%s: mount fs on '%s' %s\n", __func__, fs[i].mount_point, (ret == 0) ? "succeed" : "failed"); 422 } 423 return HDF_SUCCESS; 424} 425``` 426 427 428 429### C Library Adaptation 430 431In the mini system, adapting the C library is a complex process. For details, see *Solution to Smooth Switchover Between musl and newlib for LiteOS-M Kernel*. The toolchain uses the `newlib` C library of the [gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2](https://gitee.com/link?target=https%3A%2F%2Fdeveloper.arm.com%2F-%2Fmedia%2FFiles%2Fdownloads%2Fgnu-rm%2F10.3-2021.10%2Fgcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2). In light of this, the `newlib` C library is used for system porting. Select `newlib` in `make menuconfig` of the kernel, as shown below. 432 433![image-20211212191013553](figures/bes2600_newlib_make_menuconfig.png) 434 435#### malloc Adaptation 436 437For details, see [The Red Hat newlib C Library-malloc](https://sourceware.org/newlib/libc.html#malloc). You can use either of the following methods to implement malloc adaptation: 438 439- Implement the `_sbrk_r` function. In this method, the memory allocation function in `newlib` is used. 440 441- Implement `_malloc_r`, `_realloc_r`, `_reallocf_r`, `_free_r`, `_memalign_r`, and `_malloc_usable_size_r`. In this method, the memory allocation function in the kernel can be used. 442 443To facilitate memory allocation algorithm optimization and fault locating based on services, the latter method is used in this example. 444 445First, as the symbols of the functions in the second method already exist in `newlib`, you need to use the `wrap` link option of `gcc` to replace these function symbols with the kernel implementation code in `//kernel/liteos_m/kal/libc/newlib/porting/src/malloc.c`. 446 447Then, add the `wrap` link option of these functions to `//device/board/fnlink/v200zr/liteos_m/config.gni`. 448 449``` 450board_ld_flags += [ 451 "-Wl,--wrap=_malloc_r", 452 "-Wl,--wrap=_realloc_r", 453 "-Wl,--wrap=_reallocf_r", 454 "-Wl,--wrap=_free_r", 455 "-Wl,--wrap=_memalign_r", 456 "-Wl,--wrap=_malloc_usable_size_r", 457] 458``` 459 460#### vsprintf and Related Adaptation 461 462Implement `vprintf`, `vfprintf`, `printf`, `snprintf`, and `sprintf`. For details, see [vfprintf](https://sourceware.org/newlib/libc.html#vfprintf). 463 464Similar to `malloc` adaptation, the implementation of these functions must be provided first, that is, `//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/printf.c`. In this example, the friendly implementation of the open-source protocol is used. Different from `malloc` adaptation, this function is provided by the SoC vendor. This is because the implementation size varies in terms of printing based on the project requirements, and therefore the kernel cannot provide a unified implementation. 465 466Then, add the `wrap` link option of these functions to `//device/board/fnlink/v200zr/liteos_m/config.gni`. 467 468``` 469board_ld_flags += [ 470 "-Wl,--wrap=printf", 471 "-Wl,--wrap=sprintf", 472 "-Wl,--wrap=snprintf", 473 "-Wl,--wrap=vsnprintf", 474 "-Wl,--wrap=vprintf", 475] 476``` 477 478#### open and Related Adaptation 479 480The adaptation is implemented by the kernel and does not need attention from the SoC. The kernel file `//kernel/liteos_m/kal/libc/newlib/porting/src/fs.c` has been adapted to the `_read`, `_write`, and other related functions of `newlib`, as shown below. 481 482``` 483... 484ssize_t _read(int fd, void *buf, size_t nbyte) 485{ 486 return LOS_Read(fd, buf, nbyte); 487} 488 489ssize_t _write(int fd, const void *buf, size_t nbyte) 490{ 491 return LOS_Write(fd, buf, nbyte); 492} 493 494off_t _lseek(int fd, off_t offset, int whence) 495{ 496 return LOS_Lseek(fd, offset, whence); 497} 498... 499``` 500 501## Board-Level OS Porting 502 503### Driver Porting 504 505#### Porting the HDF Driver for the SoC Platform 506 507Driver adaptation files are stored in `drivers/adapter/platform`, including `gpio`, `i2c`, `pwm`, `spi`, `uart`, and `watchdog`, which are loaded using the `HDF` mechanism. This section uses `gpio` as an example. 508 509##### GPIO Driver Adaptation 510 511The `gpio` driver adaptation requires building adaptation and source code adaptation. 512 513The `//drivers/adapter/platform/gpio/BUILD.gn` file describes the building adaptation of the `gpio` driver, as shown below: 514 515``` 516module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO) --- If the GPIO configuration switch of the HDF is enabled, the following is built: 517module_name = get_path_info(rebase_path("."), "name") 518 519hdf_driver(module_name) { 520 sources = [] 521 if (defined(LOSCFG_SOC_COMPANY_BESTECHNIC)) { --- If the Bestechnic SoC configuration switch is enabled, the Bestechnic GPIO driver is built. 522 sources += [ "gpio_bes.c" ] 523 } 524 525 include_dirs = [ "." ] 526} 527``` 528 529The `//drivers/adapter/platform/gpio/gpio_bes.c` file describes the source code adaptation of the Bestechnic GPIO driver. 530First, load the basic driver adaptation framework based on OpenHarmony `HDF`, as shown below: 531 532``` 533struct HdfDriverEntry g_GpioDriverEntry = { 534 .moduleVersion = 1, 535 .moduleName = "BES_GPIO_MODULE_HDF", 536 .Bind = GpioDriverBind, 537 .Init = GpioDriverInit, 538 .Release = GpioDriverRelease, 539}; 540HDF_INIT(g_GpioDriverEntry); --- Load the GPIO driver through HDF_INIT. 541``` 542 543Then, obtain the `hcs` parameter for initialization as follows: 544 545``` 546static int32_t GpioDriverInit(struct HdfDeviceObject *device) 547{ 548 int32_t ret; 549 struct GpioCntlr *gpioCntlr = NULL; 550 551 if (device == NULL) { 552 HDF_LOGE("%s: device is NULL", __func__); 553 return HDF_ERR_INVALID_PARAM; 554 } 555 556 gpioCntlr = GpioCntlrFromDevice(device); --- Obtain the GPIO configuration. 557 if (gpioCntlr == NULL) { 558 ... 559``` 560 561 562 563#### Porting the HDF Drivers of Peripheral Components on the Board 564 565Peripheral components are connected to the board through the `SoC` bus. In this example, the peripheral component is a display, whose driver adaptation code is stored in the `//device/board/fnlink/drivers/liteos_m` directory. 566 567##### Display Driver Adaptation 568 569The display driver adaptation process is similar to the `SoC` driver adaptation process. In the `//device/board/fnlink/drivers/liteos_m/display/BUILD.gn` file, load the driver module based on the `hdf_driver` template, as shown below: 570 571``` 572module_name = get_path_info(rebase_path("."), "name") 573hdf_driver(module_name) { 574 sources = [ 575 "zzw395.c", 576 ] 577 include_dirs = [ 578 "//drivers/peripheral/display/interfaces/include", 579 ... 580 ] 581} 582``` 583 584In the `//device/board/fnlink/drivers/liteos_m/display/zzw395.c` file, load the display driver based on HDF, as shown below: 585 586``` 587static struct HdfDriverEntry g_ZZW395DriverEntry = { 588 .moduleVersion = 1, 589 .moduleName = "HDF_PANEL_ZZW395", 590 .Bind = PanelDriverBind, 591 .Init = PanelDriverInit, 592 .Release = PanelDriverRelease, 593}; 594 595HDF_INIT(g_ZZW395DriverEntry); 596``` 597 598Configure the driver parameters based on `hcs`, which are loaded during `PanelDriverInit` initialization. The sample code is as follows: 599 600``` 601static int32_t PanelDriverInit(struct HdfDeviceObject *object) 602{ 603 if (object == NULL) { 604 return HDF_FAILURE; 605 } 606 HDF_LOGD("%s entry !!!", __func__); 607 if (object->property) { 608 if (PanelGetResource(&priv, object->property) != HDF_SUCCESS) { 609 HDF_LOGE("%s: PanelGetResource failed", __func__); 610 return HDF_FAILURE; 611 } 612 } 613... 614``` 615 616### Adapting OpenHarmony Subsystems 617 618The adaptation of OpenHarmony subsystems consists of two parts: 619 620- Add the target subsystem and component to the `config.json` file so that the component can be included in the compilation by the compilation system. 621- Perform hardware adaptation or optional software adaptation for the `HAL` layer APIs of the component. 622 623#### Communication Subsystem Adaptation 624 625##### wifi_lite Component Adaptation 626 627Add the `wifi_lite` component of the `communication` subsystem to the `config.json` file. 628 629``` 630 { 631 "subsystem": "communication", 632 "components": [ 633 { 634 "component": "wifi_lite", 635 "optional": "true" 636 } 637 ] 638 }, 639``` 640 641The `wifi_lite` component is described in the `//build/lite/components/communication.json` file as follows: 642 643``` 644 { 645 "component": "wifi_lite", 646... 647 "targets": [ 648 "//foundation/communication/wifi_lite:wifi" --- wifi_lite in the compilation targets 649 ], 650... 651 }, 652 653``` 654 655In the `//foundation/communication/wifi_lite/BUILD.gn` file, describe the path of the API header file to be adapted as follows: 656 657``` 658config("include") { 659 include_dirs = [ "interfaces/wifiservice" ] --- The wifi_lite component provides the header file but not the implementation. Therefore, it exposes the adaptation directory to the hardware vendor for adaptation. The vendor provides the Wi-Fi protocol stack source code for implementation. 660} 661 662group("wifi") { 663 public_configs = [ ":include" ] 664} 665``` 666 667In this example, Wi-Fi is provided by `SoC`. Therefore, the Wi-Fi adaptation source code is stored in the `//device/soc/bestechnic/hals/communication/wifi_lite/wifiservice` directory of `SoC`, which contains `wifi_device.c` and `wifi_hotspot.c` to adapt to `wifi_device.h` and `wifi_hotspot.h`, respectively. The sample code is as follows: 668 669``` 670... 671WifiErrorCode Scan(void) --- Wi-Fi hotspot scanning function in wifi_device.c, which is used to adapt to the Scan function in wifi_device.h. 672{ 673 WifiErrorCode ret = ERROR_WIFI_BUSY; 674 675 676 if (IsWifiActive() != WIFI_STA_ACTIVE) 677 return ERROR_WIFI_IFACE_INVALID; 678 679 if (g_HalHmosWifiInfo.scan_state == SCAN_REQUEST || 680 g_HalHmosWifiInfo.scan_state == SCAN_TRIGGER) 681 return ERROR_WIFI_BUSY; 682 683 HalHmosWifiLock(); 684 ret = ((HalHmosSendEvent(HMOS_ON_WIFI_SCAN_STATE_CHANGED, NULL) == 0) ? WIFI_SUCCESS : ERROR_WIFI_BUSY); 685 HalHmosWifiUnLock(); 686 687 return ret; 688} 689... 690int GetSignalLevel(int rssi, int band) --- Function in wifi_hotspot.c for obtaining Wi-Fi hotspot parameters, which is used to adapt to the GetSignalLevel function in wifi_hotspot.h. 691{ 692 if (band == HOTSPOT_BAND_TYPE_2G) { 693 if (rssi >= RSSI_LEVEL_4_2_G) 694 return RSSI_LEVEL_4; 695 if (rssi >= RSSI_LEVEL_3_2_G) 696 return RSSI_LEVEL_3; 697 if (rssi >= RSSI_LEVEL_2_2_G) 698 return RSSI_LEVEL_2; 699 if (rssi >= RSSI_LEVEL_1_2_G) 700 return RSSI_LEVEL_1; 701 } 702 703 if (band == HOTSPOT_BAND_TYPE_5G) { 704 if (rssi >= RSSI_LEVEL_4_5_G) 705 return RSSI_LEVEL_4; 706 if (rssi >= RSSI_LEVEL_3_5_G) 707 return RSSI_LEVEL_3; 708 if (rssi >= RSSI_LEVEL_2_5_G) 709 return RSSI_LEVEL_2; 710 if (rssi >= RSSI_LEVEL_1_5_G) 711 return RSSI_LEVEL_1; 712 } 713 return ERROR_WIFI_INVALID_ARGS; 714} 715``` 716 717##### lwIP Component Adaptation 718 719By default, `lwip` is configured in the `LiteOS-M kernel` directory. Therefore, you can include the `lwip` directory in the `kernel` component for compilation. The sample code is as follows: 720 721``` 722 { 723 "subsystem": "kernel", 724 "components": [ 725 { 726 "component": "liteos_m", 727 "features": [ 728 "ohos_kernel_liteos_m_lwip_path = \"//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1\"" --- Specify the SoC vendor directory for compilation. 729 ] 730 } 731 ] 732 }, 733``` 734 735The `//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/BUILD.gn` file describes the compilation of `lwip` as follows: 736 737``` 738import("//kernel/liteos_m/liteos.gni") 739import("$LITEOSTHIRDPARTY/lwip/lwip.gni") 740import("$LITEOSTOPDIR/components/net/lwip-2.1/lwip_porting.gni") 741 742module_switch = defined(LOSCFG_NET_LWIP_SACK) 743module_name = "lwip" 744kernel_module(module_name) { 745 sources = LWIP_PORTING_FILES + LWIPNOAPPSFILES - 746 [ "$LWIPDIR/api/sockets.c" ] + [ "porting/src/ethernetif.c" ] --- Add the ethernetif.c file to adapt to the initialization of the Ethernet adapter. 747 defines = [ "LITEOS_LWIP=1" ] 748 defines += [ "CHECKSUM_BY_HARDWARE=1" ] 749} 750 751config("public") { 752 defines = [ "_BSD_SOURCE=1" ] 753 include_dirs = 754 [ "porting/include" ] + LWIP_PORTING_INCLUDE_DIRS + LWIP_INCLUDE_DIRS 755} 756 757``` 758 759In the `//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/include/lwip/lwipopts.h` file, retain the original `lwip` configuration, on which the software bus depends, and add the following hardware adaptation options: 760 761``` 762#ifndef _PORTING_LWIPOPTS_H_ 763#define _PORTING_LWIPOPTS_H_ 764 765#include_next "lwip/lwipopts.h" --- Retain the original configuration. 766 767#define LWIP_NETIF_STATUS_CALLBACK 1 768#define LWIP_CHECKSUM_ON_COPY 0 769#define CHECKSUM_GEN_UDP 0 --- Add hardware adaptation options. 770 771#endif /* _PORTING_LWIPOPTS_H_ */ 772 773``` 774 775In the `//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/src/ethernetif.c` file, add the adaptation to the initialization of the Ethernet adapter as follows: 776 777``` 778err_t 779ethernetif_init(struct netif *netif) 780{ 781... 782#ifdef CHECKSUM_BY_HARDWARE 783 eth_hw_checksum_init(); 784#endif 785... 786 netif->linkoutput = low_level_output; 787 788 netif->drv_send = liteos_low_level_output; 789 netif->hwaddr_len = NETIF_MAX_HWADDR_LEN; 790 low_level_init(netif); 791 driverif_init(netif); 792 return ERR_OK; 793... 794} 795``` 796 797##### dsoftbus Component Adaptation 798 799Add the `dsoftbus` component to the `config.json` file as follows: 800 801``` 802{ 803 "component": "dsoftbus", 804 "features": [ 805 "softbus_adapter_config = \"//vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config\"" 806 ] 807}, 808``` 809 810The `dsoftbus` component provides the `softbus_adapter_config` configuration option in the `//foundation/communication/dsoftbus/dsoftbus.gni` file for configuration during porting. The configuration specifies the path for DSoftBus porting adaptation. 811 812In this example, `softbus_adapter_config` is set to `//vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config`. The structure of this path is as follows: 813 814``` 815. 816├── feature_config --- DSoftBus configuration, for example, whether to enable self-discovery. 817│ └── mini 818│ └── config.gni 819└── spec_config --- DSoftBus configuration, for example, the DSoftBus log level. 820 ├── softbus_config_adapter.c 821 ├── softbus_config_adapter.h 822 └── softbus_config_type.h 823``` 824 825The following configuration items are defined in the `config.gni` file: 826 827| Item | Description | 828| ------------------------------------------ | ------------------------ | 829| dsoftbus_feature_disc_ble | Whether to enable BLE discovery. | 830| dsoftbus_feature_disc_coap | Whether to enable CoAP discovery. | 831| dsoftbus_feature_conn_tcp | Whether to enable TCP connection. | 832| dsoftbus_feature_conn_br | Whether to enable BR connection. | 833| dsoftbus_feature_conn_ble | Whether to enable BLE connection. | 834| dsoftbus_feature_conn_p2p | Whether to enable P2P connection. | 835| dsoftbus_feature_trans_udp | Whether to enable UDP transmission. | 836| dsoftbus_feature_trans_udp_stream | Whether to enable the UDP transport stream. | 837| dsoftbus_feature_trans_udp_file | Whether to enable UDP file transfer. | 838| dsoftbus_feature_ip_auth | Whether to enable transmission channel authentication.| 839| dsoftbus_feature_auth_account | Whether to enable account-based authentication.| 840| dsoftbus_feature_qos | Whether to enable QoS. | 841 842The following configuration items are defined in the `softbus_config_adapter.c` file: 843 844| Item | Description | 845| ------------------------------------ | ----------------------------- | 846| SOFTBUS_INT_MAX_BYTES_LENGTH | SendBytes: maximum number of bytes that can be sent. | 847| SOFTBUS_INT_MAX_MESSAGE_LENGTH | SendMessage: maximum length of a message that can be sent.| 848| SOFTBUS_INT_CONN_BR_MAX_DATA_LENGTH | Maximum volume of data received over Bluetooth. | 849| SOFTBUS_INT_CONN_RFCOM_SEND_MAX_LEN | Maximum volume of data sent over Bluetooth. | 850| SOFTBUS_INT_ADAPTER_LOG_LEVEL | Log level. | 851| SOFTBUS_STR_STORAGE_DIRECTORY | Storage directory. | 852 853After DSoftBus is configured, it is not started by default. Therefore, you need to invoke the `InitSoftBusServer` function through the startup framework as follows: 854 855``` 856static void DSoftBus(void) 857{ 858 osThreadAttr_t attr; 859 attr.name = "dsoftbus task"; 860 attr.attr_bits = 0U; 861 attr.cb_mem = NULL; 862 attr.cb_size = 0U; 863 attr.stack_mem = NULL; 864 attr.stack_size = 65536; 865 attr.priority = 24; 866 867 extern void InitSoftBusServer(void); 868 if (osThreadNew((osThreadFunc_t) InitSoftBusServer, NULL, &attr) == NULL) { 869 printf("Failed to create WifiSTATask!\n"); 870 } 871} 872 873APP_FEATURE_INIT(DSoftBus); 874``` 875 876##### RPC Component Adaptation 877 878Add the following `rpc` configuration to the `config.json` file: 879 880``` 881{ 882 "component": "rpc" 883}, 884``` 885 886Similarly, for the `rpc` component, you need to invoke the `StartDBinderService` function through the startup framework. The running of this function depends on the `IP` address obtained by the host. Therefore, invoke this function in the callback of the IP address change event registered by the lwIP protocol stack as follows: 887 888``` 889static void RpcServerWifiDHCPSucCB(struct netif *netif, netif_nsc_reason_t reason, 890 const netif_ext_callback_args_t *args) 891{ 892 (void) args; 893 if (netif == NULL) { 894 printf("%s %d, error: input netif is NULL!\n", __FUNCTION__, __LINE__); 895 return; 896 } 897 if (reason == LWIP_NSC_IPSTATUS_CHANGE) { 898 if (netif_is_up(netif) && !ip_addr_isany(&netif->ip_addr)) { 899 printf("%s %d, start rpc server!\n", __FUNCTION__, __LINE__); 900 StartDBinderService(); 901 } 902 } 903} 904 905static void WifiDHCPRpcServerCB(void) 906{ 907 NETIF_DECLARE_EXT_CALLBACK(WifiReadyRpcServerCallback); 908 netif_add_ext_callback(&WifiReadyRpcServerCallback, RpcServerWifiDHCPSucCB); 909} 910 911APP_FEATURE_INIT(WifiDHCPRpcServerCB); 912``` 913 914#### Startup Subsystem Adaptation 915 916For the `startup` subsystem, adapt the `bootstrap_lite` and `syspara_lite` components. Add the corresponding configuration items to the `vendor/bestechnic_bak/display_demo/config.json` file, as shown below: 917 918``` 919{ 920 "subsystem": "startup", 921 "components": [ 922 { 923 "component": "bootstrap_lite" --- bootstrap_lite component 924 }, 925 { 926 "component": "syspara_lite", --- syspara_lite component 927 "features": [ 928 "enable_ohos_startup_syspara_lite_use_posix_file_api = true" 929 ] 930 } 931 ] 932}, 933``` 934 935When adapting the `bootstrap_lite` component, you need to add the following code snippet to the `//device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/out/best2600w_liteos/_best2001.lds` file: 936 937``` 938 __zinitcall_bsp_start = .; 939 KEEP (*(.zinitcall.bsp0.init)) 940 KEEP (*(.zinitcall.bsp1.init)) 941 KEEP (*(.zinitcall.bsp2.init)) 942 KEEP (*(.zinitcall.bsp3.init)) 943 KEEP (*(.zinitcall.bsp4.init)) 944 __zinitcall_bsp_end = .; 945 __zinitcall_device_start = .; 946 KEEP (*(.zinitcall.device0.init)) 947 KEEP (*(.zinitcall.device1.init)) 948 KEEP (*(.zinitcall.device2.init)) 949 KEEP (*(.zinitcall.device3.init)) 950 KEEP (*(.zinitcall.device4.init)) 951 __zinitcall_device_end = .; 952 __zinitcall_core_start = .; 953 KEEP (*(.zinitcall.core0.init)) 954 KEEP (*(.zinitcall.core1.init)) 955 KEEP (*(.zinitcall.core2.init)) 956 KEEP (*(.zinitcall.core3.init)) 957 KEEP (*(.zinitcall.core4.init)) 958 __zinitcall_core_end = .; 959 __zinitcall_sys_service_start = .; 960 KEEP (*(.zinitcall.sys.service0.init)) 961 KEEP (*(.zinitcall.sys.service1.init)) 962 KEEP (*(.zinitcall.sys.service2.init)) 963 KEEP (*(.zinitcall.sys.service3.init)) 964 KEEP (*(.zinitcall.sys.service4.init)) 965 __zinitcall_sys_service_end = .; 966 __zinitcall_sys_feature_start = .; 967 KEEP (*(.zinitcall.sys.feature0.init)) 968 KEEP (*(.zinitcall.sys.feature1.init)) 969 KEEP (*(.zinitcall.sys.feature2.init)) 970 KEEP (*(.zinitcall.sys.feature3.init)) 971 KEEP (*(.zinitcall.sys.feature4.init)) 972 __zinitcall_sys_feature_end = .; 973 __zinitcall_run_start = .; 974 KEEP (*(.zinitcall.run0.init)) 975 KEEP (*(.zinitcall.run1.init)) 976 KEEP (*(.zinitcall.run2.init)) 977 KEEP (*(.zinitcall.run3.init)) 978 KEEP (*(.zinitcall.run4.init)) 979 __zinitcall_run_end = .; 980 __zinitcall_app_service_start = .; 981 KEEP (*(.zinitcall.app.service0.init)) 982 KEEP (*(.zinitcall.app.service1.init)) 983 KEEP (*(.zinitcall.app.service2.init)) 984 KEEP (*(.zinitcall.app.service3.init)) 985 KEEP (*(.zinitcall.app.service4.init)) 986 __zinitcall_app_service_end = .; 987 __zinitcall_app_feature_start = .; 988 KEEP (*(.zinitcall.app.feature0.init)) 989 KEEP (*(.zinitcall.app.feature1.init)) 990 KEEP (*(.zinitcall.app.feature2.init)) 991 KEEP (*(.zinitcall.app.feature3.init)) 992 KEEP (*(.zinitcall.app.feature4.init)) 993 __zinitcall_app_feature_end = .; 994 __zinitcall_test_start = .; 995 KEEP (*(.zinitcall.test0.init)) 996 KEEP (*(.zinitcall.test1.init)) 997 KEEP (*(.zinitcall.test2.init)) 998 KEEP (*(.zinitcall.test3.init)) 999 KEEP (*(.zinitcall.test4.init)) 1000 __zinitcall_test_end = .; 1001 __zinitcall_exit_start = .; 1002 KEEP (*(.zinitcall.exit0.init)) 1003 KEEP (*(.zinitcall.exit1.init)) 1004 KEEP (*(.zinitcall.exit2.init)) 1005 KEEP (*(.zinitcall.exit3.init)) 1006 KEEP (*(.zinitcall.exit4.init)) 1007 __zinitcall_exit_end = .; 1008``` 1009 1010The added code snippet is for storing the external APIs provided by `bootstrap_init`, which are injected. For details about the APIs, see `//utils/native/lite/include/ohos_init.h`. The following table lists the main macros for automatic service initialization. 1011 1012| API | Description | 1013| ---------------------- | -------------------------------- | 1014| SYS_SERVICE_INIT(func) | Entry for initializing and starting a core system service.| 1015| SYS_FEATURE_INIT(func) | Entry for initializing and starting a core system feature.| 1016| APP_SERVICE_INIT(func) | Entry for initializing and starting an application-layer service. | 1017| APP_FEATURE_INIT(func) | Entry for initializing and starting an application-layer feature. | 1018 1019![](../public_sys-resources/icon-note.gif) **NOTE**<br/> 1020 You need to add a forcible link to the` lib` file generated by building the previous loaded components. 1021 1022 If the `bootstrap_lite` component is configured in the `vendor/bestechnic/display_demo/config.json` file, as shown below: 1023 1024``` 1025 { 1026 "subsystem": "startup", 1027 "components": [ 1028 { 1029 "component": "bootstrap_lite" 1030 }, 1031 ... 1032 ] 1033 }, 1034``` 1035 1036 The `bootstrap_lite` component will compile the `//base/startup/bootstrap_lite/services/source/bootstrap_service.c` file. In this file, inject the `Init` function symbol to `__zinitcall_sys_service_start` and `__zinitcall_sys_service_end` through `SYS_SERVICE_INIT`. Because the `Init` function is not explicitly called, it needs to be forcibly linked to the final image. The sample code is as follows: 1037 1038``` 1039static void Init(void) 1040{ 1041 static Bootstrap bootstrap; 1042 bootstrap.GetName = GetName; 1043 bootstrap.Initialize = Initialize; 1044 bootstrap.MessageHandle = MessageHandle; 1045 bootstrap.GetTaskConfig = GetTaskConfig; 1046 bootstrap.flag = FALSE; 1047 SAMGR_GetInstance()->RegisterService((Service *)&bootstrap); 1048} 1049SYS_SERVICE_INIT(Init); --- Once SYS (SYS_INIT) is started, the generated library needs to be forcibly linked. 1050``` 1051 1052 In the `//base/startup/bootstrap_lite/services/source/BUILD.gn` file, the save path of `libbootstrap.a` is set to `out/v200zr/display_demo/libs` as follows: 1053 1054``` 1055static_library("bootstrap") { 1056 sources = [ 1057 "bootstrap_service.c", 1058 "system_init.c", 1059 ] 1060 .... 1061``` 1062 1063 In this case, you need to add `bootstrap` under `force_link_libs` in `vendor/bestechnic/display_demo/config.json`, as shown below: 1064 1065``` 1066 "bin_list": [ 1067 { 1068 "elf_name": "wifiiot", 1069 "bsp_target_name": "best2600w_liteos", 1070 "signature": "false", 1071 "burn_name": "rtos_main", 1072 "enable": "true", 1073 "force_link_libs": [ 1074 "bootstrap", --- Forcibly link to libbootstrap.a. 1075 ... 1076 ] 1077 }, 1078``` 1079 1080 1081 1082When the `syspara_lite` component is adapted, system parameters are written to a file for persistent storage. In the mini system, file operation APIs include `POSIX` and `HalFiles`. 1083 1084For access to the file system in the kernel, use the `POSIX` API, which means you need to add `enable_ohos_startup_syspara_lite_use_posix_file_api = true` to the `features` field. 1085 1086If you are using the `HalFiles` API, no modification is required. 1087 1088During adaptation of the `GetSerial` API, no `Serial Number` is written to the development board, which is different from the case in the production line. Therefore, you need to assign an attribute to uniquely identify the development board. In this example, the Wi-Fi MAC address is used. 1089 1090``` 1091#define ETH_ALEN 6 1092#define MAC_BITS 4 1093#define MAC_HIGH_MASK 0xf0 1094#define MAC_LOW_MASK 0x0f 1095#define HEX_A 0xa 1096#define CHAR_NUM_OFFSET 0x30 1097#define CHAR_CAPITAL_OFFSET 0x37 1098#define STR_END_FLAG '\0' 1099 1100typedef unsigned char u8; 1101 1102static char serialNumber[2*ETH_ALEN + 1]; --- The last character is used as the end character '\0'. 1103 1104 1105static char Hex2Char(u8 hex) 1106{ 1107 if (hex < HEX_A) { 1108 return hex + CHAR_NUM_OFFSET; --- Convert the value 0 to char '0'. 1109 } else { 1110 return hex + CHAR_CAPITAL_OFFSET; --- Convert the value 0xa to char 'A'. 1111 } 1112} 1113 1114const char* HalGetSerial(void) 1115{ 1116 char macAddr[ETH_ALEN]; 1117 // as devboard has no production serial number, we just 1118 // use wifi mac address as device serial number. 1119 if (serialNumber[0] == STR_END_FLAG) { --- The MAC address is obtained only when the API is invoked for the first time. 1120 extern int bwifi_get_own_mac(u8 *addr); 1121 bwifi_get_own_mac(macAddr); --- Obtain the MAC address. 1122 int j = 0; 1123 for (int i = 0; i < ETH_ALEN; i++) { 1124 u8 lowFour, highFour; 1125 highFour = (macAddr[i] & MAC_HIGH_MASK) >> MAC_BITS; 1126 serialNumber[j] = Hex2Char(highFour); 1127 j++; 1128 lowFour = macAddr[i] & MAC_LOW_MASK; 1129 serialNumber[j] = Hex2Char(lowFour); 1130 j++; 1131 } --- Convert the MAC address to the serial number. 1132 } 1133 return serialNumber; 1134} 1135``` 1136 1137#### DFX Subsystem Adaptation 1138 1139To adapt the DFX subsystem, you need to add the `hilog_lite` component in the `config.json` file. 1140 1141``` 1142{ 1143 "subsystem": "hiviewdfx", 1144 "components": [ 1145 { 1146 "component": "hilog_lite", 1147 "optional": "true" 1148 } 1149 ] 1150}, 1151``` 1152 1153Register the log output implementation function in `//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c`. 1154 1155``` 1156boolean HilogProc_Impl(const HiLogContent *hilogContent, uint32 len) 1157{ 1158 char tempOutStr[LOG_FMT_MAX_LEN] = {0}; 1159 if (LogContentFmt(tempOutStr, sizeof(tempOutStr), hilogContent) > 0) { 1160 printf(tempOutStr); 1161 } 1162 return TRUE; 1163} 1164 1165HiviewRegisterHilogProc(HilogProc_Impl); 1166``` 1167 1168#### systemabilitymgr Subsystem Adaptation 1169 1170To adapt the `systemabilitymgr` subsystem, you need to add the `samgr_lite` component in the `config.json` file, as shown below: 1171 1172``` 1173{ 1174 "subsystem": "systemabilitymgr", 1175 "components": [ 1176 { 1177 "component": "samgr_lite", 1178 "features": [ 1179 "config_ohos_systemabilitymgr_samgr_lite_shared_task_size = 4096" 1180 ] 1181 } 1182 ] 1183}, 1184``` 1185 1186In the mini system, the default size of the shared task stack for `samgr_lite` is `0x800`. To avoid stack overflow, adjust the size to `0x1000`. 1187 1188#### Security Subsystem Adaptation 1189 1190To adapt the `security` subsystem, you need to add the `huks/deviceauth_lite` component in the `config.json` file, as shown below: 1191 1192``` 1193 { 1194 "subsystem": "security", 1195 "components": [ 1196 { 1197 "component": "huks", 1198 "features": [ 1199 "huks_use_lite_storage = true", 1200 "huks_use_hardware_root_key = true", 1201 "huks_config_file = \"hks_config_lite.h\"", 1202 "huks_key_store_path = \"/data/\"", 1203 "ohos_security_huks_mbedtls_porting_path = \"//device/soc/bestechnic/hals/mbedtls\"" 1204 ] 1205 }, 1206 { 1207 "component": "deviceauth_lite", 1208 "features": [ 1209 "deviceauth_storage_path = \"/data/\"", 1210 "deviceauth_hichain_thread_stack_size = 9472" 1211 ] 1212 } 1213 ] 1214 } 1215``` 1216 1217During `huks` component adaptation, set `huks_key_store_path` to the path for storing the key and `ohos_security_huks_mbedtls_porting_path` to the directory for `mbedtls` adaptation, so that the chip can adapt `mbedtls` to hardware random numbers. 1218 1219During `deviceauth_lite` component adaptation, set `deviceauth_storage_path` to the path for storing device authentication information and `deviceauth_hichain_thread_stack_size` to the thread stack size. 1220 1221#### Multimedia Subsystem Adaptation 1222 1223To adapt the multimedia subsystem, you need to add the `histreamer` component in the `config.json` file, as shown below: 1224 1225``` 1226{ 1227 "subsystem": "multimedia", 1228 "components": [ 1229 { 1230 "component": "histreamer", 1231 "features": [ 1232 "multimedia_histreamer_enable_plugin_hdi_adapter = true", 1233 "multimedia_histreamer_enable_plugin_minimp3_adapter = true", 1234 "multimedia_histreamer_enable_plugin_ffmpeg_adapter = false", 1235 "config_ohos_multimedia_histreamer_stack_size = 65536" 1236 ] 1237 } 1238 ] 1239}, 1240``` 1241 1242The configuration items of the `histreamer` component are described as follows: 1243 1244| Item | Description | 1245| --------------------------------------------------- | ------------------------------- | 1246| multimedia_histreamer_enable_plugin_hdi_adapter | Whether to enable histreamer to connect to the HDMI interface.| 1247| multimedia_histreamer_enable_plugin_minimp3_adapter | Whether to enable the plug-in to adapt to miniMP3. | 1248| multimedia_histreamer_enable_plugin_ffmpeg_adapter | Whether to enable the plug-in to adapt to FFmpeg. | 1249| config_ohos_multimedia_histreamer_stack_size | Size of the histreamer stack. | 1250 1251#### utils Subsystem Adaptation 1252 1253To adapt the `utils` subsystem, you need to add the `kv_store`, `js_builtin`, `timer_task`, and `kal_timer` components in the `config.json` file, as shown below: 1254 1255``` 1256{ 1257 "subsystem": "utils", 1258 "components": [ 1259 { 1260 "component": "kv_store", 1261 "features": [ 1262 "enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true" 1263 ] 1264 }, 1265 { 1266 "component": "js_builtin" 1267 }, 1268 { 1269 "component": "timer_task" 1270 }, 1271 { 1272 "component": "kal_timer", 1273 } 1274 ] 1275}, 1276``` 1277 1278Similar to that in the `syspara_lite` component, the key-value pair is written to a file during adaptation of the `kv_store` component. In the mini system, file operation APIs include `POSIX` and `HalFiles`. For access to the file system in the kernel, use the `POSIX` API, which means that you need to add `enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true` to the `features` field. If you are using the `HalFiles` API, no modification is required. 1279 1280#### Graphics Subsystem Adaptation 1281 1282To adapt the `graphic` subsystem, you need to add the `graphic_utils` component in the `config.json` file, as shown below: 1283 1284``` 1285 "components": [ 1286 { 1287 "component": "graphic_utils", 1288 "features": [ 1289 "enable_ohos_graphic_utils_product_config = true" 1290 ] 1291 }, 1292 { 1293 "component": "ui" 1294 } 1295 ] 1296 } 1297``` 1298 1299For details about `graphic` configuration, see `//vendor/bestechnic/display_demo/graphic_config/product_graphic_lite_config.h`. 1300 1301For details about `graphic` adaptation, see `//device/soc/bestechnic/bes2600/liteos_m/components/ui`, . The main functions are as follows: 1302 1303- `display_device`: instantiates `BaseGfxEngine`. 1304- `touch_input`: instantiates `PointerInputDevice`. 1305- `UiMainTask`: initializes the font engine and executes rendering tasks. 1306 1307Layers of the `graphic` subsystem: 1308 1309``` 1310aafwk_lite + appexecfwk_lite (AAFWK + APPEXECFWK) 1311 | 1312ace_engine_lite + jerryscript + i18n_lite + resmgr_lite + utils/native/lite/... (ACE and JS engines and their dependencies) 1313 | 1314graphic_ui + graphic_utils (Graphic framework) 1315 | 1316giflib + libjpeg + libpng + qrcodegen + freetype... (Third-party graphics library) 1317``` 1318 1319For details about the graphic application demo, see the `//vendor/bestechnic/display_demo/tests/app.cpp` file, as shown below: 1320 1321``` 1322/* ui app entry */ 1323void RunApp() 1324{ 1325#ifdef UI_TEST 1326 AnimatorDemoStart(); --- native ui demo 1327#elif defined(ABILITY_TEST) 1328 StartJSApp(); --- js demo 1329#endif 1330} 1331 1332void AppEntry(void) 1333{ 1334 UiMain(); 1335} 1336 1337APP_FEATURE_INIT(AppEntry); 1338``` 1339 1340#### ACE Subsystem Adaptation 1341 1342To adapt the ACE subsystem, you need to add the `ace_engine_lite` component in the `config.json` file, as shown below: 1343 1344 { 1345 "subsystem": "ace", 1346 "components": [ 1347 { 1348 "component": "ace_engine_lite", 1349 "features": [ 1350 "enable_ohos_ace_engine_lite_product_config = true" 1351 ] 1352 } 1353 ] 1354 }, 1355 1356For details about the `ace_engine_lite` configuration, see `//vendor/bestechnic/display_demo/ace_lite_config/product_acelite_config.h`. 1357 1358The `ace_lite` application is developed in JavaScript. The detailed procedure is as follows: 1359 13601. Use DevEco Studio to compile a JavaScript application. For details, see [Lite Wearable Development Specifications](https://developer.harmonyos.com/en/docs/documentation/doc-references/lite-wearable-file-0000001176751380). 13612. Use the Previewer feature to preview the application and obtain the JS package `entry\.preview\intermediates\res\debug\lite\assets\js\default`. 13623. Place the JS package to the corresponding file system path `vendor/bestechnic/display_demo/fs/data/data/js`, as shown below: 1363 1364``` 1365├── app.js 1366├── common 1367├── i18n 1368├── manifest.json 1369└── pages 1370``` 1371 13724. Start building to generate the system image. Burn the system image the development board, and the system will load and start the `ace` application from `app.js`. 1373 1374#### aafwk Subsystem Adaptation 1375 1376To adapt the `aafwk` subsystem, you need to add the `aafwk_lite` component in the `config.json` file, as shown below: 1377 1378``` 1379 { 1380 "subsystem": "aafwk", 1381 "components": [ 1382 { 1383 "component": "aafwk_lite", 1384 "features": [ 1385 "enable_ohos_appexecfwk_feature_ability = true", --- Enable the FA to support the graphics capability. 1386 "config_ohos_aafwk_ams_task_size = 4096" --- Configure the size of the aafwk stack. 1387 ] 1388 } 1389 ] 1390 }, 1391``` 1392 1393For details about the `aafwk_lite` use cases, see the `vendor/bestechnic/display_demo/tests/ability` directory, which includes the `launcher` and `js app` applications. The function invocation process of the applications is described as follows: 1394 13951. `launcher` application: Use `InstallLauncher` to install the `native ui` application, whose `BundleName` is `"com.example.launcher"`. After `AbilityMgrSliteFeature` is started, `AbilityMgrHandler::StartLauncher()` is invoked to start the `launcher` application. 1396 13972. `StartJSApp` application: Use `StartAbility` to start any `Want` and pass `want data` to `JS_APP_PATH`, 1398 `SetWantData(&want, JS_APP_PATH, strlen(JS_APP_PATH) + 1)`. 1399 1400#### appexecfwk Subsystem Adaptation 1401 1402To adapt the `appexecfwk` subsystem, you need to add the `appexecfwk_lite` component in the `config.json` file, as shown below: 1403 1404``` 1405 { 1406 "subsystem": "appexecfwk", 1407 "components": [ 1408 { 1409 "component": "appexecfwk_lite" 1410 } 1411 ] 1412 }, 1413``` 1414 1415## Compatibility Test 1416 1417### Product Compatibility Specifications 1418 1419For details about product compatibility specifications, see [Introduction to Product Compatibility SIG](https://gitee.com/openharmony-sig/compatibility/tree/master). 1420 1421### XTS Test Cases 1422 1423For details about the `XTS` test cases, see [XTS](../device-test/xts.md). To adapt the `XTS` subsystem, you need to add the `xts_acts`/`xts_tools` component in the `config.json` file, as shown below: 1424 1425 { 1426 "subsystem": "xts", 1427 "components": [ 1428 { "component": "xts_acts", "features": 1429 [ 1430 "config_ohos_xts_acts_utils_lite_kv_store_data_path = \"/data\"", 1431 "enable_ohos_test_xts_acts_use_thirdparty_lwip = true" 1432 ] 1433 }, 1434 { "component": "xts_tools", "features":[] } 1435 ] 1436 } 1437 1438Where: 1439 1440- `config_ohos_xts_acts_utils_lite_kv_store_data_path` is the name of the root directory to which the file system is mounted. 1441- `enable_ohos_test_xts_acts_use_thirdparty_lwip` indicates whether to use the source code in the `thirdparty/lwip` directory. The value `true` means to use the source code in the `thirdparty/lwip` directory, and `false` means the opposite. 1442 1443After the execution is complete, `xx Tests xx Failures xx Ignored` is displayed, as shown below: 1444 1445``` 1446... 1447[16:53:43:438]../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:793:testKvStoreMaxSize004:PASS 1448[16:53:43:438]+-------------------------------------------+ 1449[16:53:43:438] 1450[16:53:43:438]----------------------- 1451[16:53:43:438]32 Tests 0 Failures 0 Ignored 1452[16:53:43:438]OK 1453[16:53:43:439]All the test suites finished! 1454``` 1455 1456### Report Submission 1457 1458Save the preceding `XTS` test result as a test report and upload it to the OpenHarmony compatibility test website. This is a prerequisite for synchronizing the code from the `sig` repository to the `master` repository. The procedure is as follows: 1459 1460Step 1: Compress the `XTS` test report into a `zip` file. 1461 1462Step 2: Generate the SHA checksum of the test report. In this example, the SHA checksum is generated by uploading the `zip` file to the [SHA checksum online generator](https://tool.lmeee.com/jiami/filehash). 1463 1464Step 3: Go to the `OpenHarmony` [compatibility test website](https://www.openharmony.cn/old/#/Compatibility_test) and upload the report. 1465 1466 - Set `API Level` to the `"sdkApiLevel"` value in the report. 1467 - Set `OS` to the `"OS Version"` value in the report. 1468 1469## Coming Soon 1470 1471The following aspects will be added in the future: 1472 1473- Bluetooth 1474- `bms` package installation 1475- Verifying `bytecode` for running `JS` 1476- Distributed capabilities: `dms` and `dm` 1477- Example of a distributed music player 1478