1# Standard System Solution – Rockchip RK3568 Porting Case
2
3This document describes how to port standard system functions based on the DAYU200 development board of the RK3568 chip from Rockchip. The porting processing mainly includes product configuration adding, kernel startup and upgrade, ADM-based conversion of audio, case summary of the camera, TP, LCD, Wi-Fi, Bluetooth, vibrator, sensor, and graphics display modules, as well as related function adaptation.
4
5## Product Configuration and Directory Planning
6
7### Product Configuration
8
9Create a JSON file named after RK3568 in the `//productdefine/common/device` directory and specify the CPU architecture. The `//productdefine/common/device/rk3568.json` file is configured is as follows:
10
11```
12{
13    "device_name": "rk3568",
14    "device_company": "rockchip",
15    "target_os": "ohos",
16    "target_cpu": "arm",
17    "kernel_version": "",
18    "device_build_path": "device/board/hihope/rk3568",
19    "enable_ramdisk": true,   // Specifies whether to support ramdisk secondary boot.
20    "build_selinux": true    // Indicates whether SELinux permission management is supported.
21}
22```
23
24Create a **rk3568.json** file in the **//productdefine/common/products** directory. This file is used to describe the SoC used by the product and the required subsystems. Configure the file as follows:
25
26```
27{
28  "product_name": "rk3568",
29  "product_company" : "hihope",
30  "product_device": "rk3568",
31  "version": "2.0",
32  "type": "standard",
33  "parts":{
34    "ace:ace_engine_standard":{},
35    "ace:napi":{},
36    ...
37    "xts:phone_tests":{}
38  }
39}
40```
41
42The main configurations are as follows:
43
441. **product_device**: SoC used by the product.
452. **type**: system type. In this example, set it to **standard**.
463. **parts**: subsystem to enable. A subsystem can be treated as an independently built functional block.
47
48You can find predefined subsystems in **//build/subsystem_config.json**. You can also customize subsystems.
49
50You are advised to copy the configuration file of Hi3516D V300 and delete the **hisilicon_products** subsystem, which is used to compile the kernel for Hi3516D V300.
51
52### Directory Planning
53
54This solution designs the directory structure using the [board and SoC decoupling idea](https://gitee.com/openharmony-sig/sig-content/blob/master/devboard/docs/board-soc-arch-design.md), and plans the SoC adaptation directory as follows:
55
56```
57device
58├── board                                --- Board vendor directory
59│   └── hihope                           --- Board vendor
60│       └── rk3568                       --- Board name, RK3568, which contains driver service code
61└── soc									 --- SoC vendor directory
62    └── rockchip                       --- SoC vendor: Rockchip
63        └── rk3568						 --- SoC series: RK3568, mainly solutions provided by the chip vendor and closed-source libraries
64
65
66```
67
68```
69vendor
70└── hihope
71    └── rk3568         			 --- Product name: product, HCS, and demo
72```
73
74## **Kernel Startup**
75
76### Secondary Boot
77
78Unlike traditional boot that directly mounts **system** and boots using **init** of **system**, secondary boot is to mount **ramdsik**, boot using **init** of **ramdsik**, perform necessary initialization operations (such as mounting the **system** and **vendor** partitions), and then switch to **init** of **system**.
79
80RK3568 adaptation is to pack **ramdisk** compiled in the mainline version into **boot_linux.img**. The procedure is as follows:
81
821. Enable secondary boot.
83
84   Set **enable_ramdisk** in **productdefine/common/device/rk3568.json**.
85
86    ```
87    {
88      "device_name": "rk3568",
89      "device_company": "hihope",
90      "target_os": "ohos",
91      "target_cpu": "arm",
92      "kernel_version": "",
93      "device_build_path": "device/hihope/build",
94      "enable_ramdisk": true,
95      "build_selinux": true
96    }
97    ```
98
992. Pack the **ramdsik.img** file compiled in the mainline version to **boot_linux.img**.
100
101   View the configuration as follows:
102
103   RK supports **uboot** from **ramdisk**. You only need to add **ramdisk.img** to the configuration file of the packed **boot_linux.img**. Therefore, the **its** format of the mainline version is not used. Specifically, add the following content to the kernel compilation script **make-ohos.sh**:
104
105     ```
106     function make_extlinux_conf()
107     {
108   	dtb_path=$1
109   	uart=$2
110   	image=$3
111
112   	echo "label rockchip-kernel-5.10" > ${EXTLINUX_CONF}
113   	echo "	kernel /extlinux/${image}" >> ${EXTLINUX_CONF}
114   	echo "	fdt /extlinux/${TOYBRICK_DTB}" >> ${EXTLINUX_CONF}
115   	if [ "enable_ramdisk" == "${ramdisk_flag}" ]; then
116   		echo "	initrd /extlinux/ramdisk.img" >> ${EXTLINUX_CONF}
117   	fi
118   	cmdline="append earlycon=uart8250,mmio32,${uart} root=PARTUUID=614e0000-0000-4b53-8000-1d28000054a9 rw rootwait rootfstype=ext4"
119   	echo "  ${cmdline}" >> ${EXTLINUX_CONF}
120     }
121     ```
122
123### Packing
124
125Add the **make-boot.sh** script for packing the boot image. This script can be called when the boot image is packed after **ramdisk** is compiled. The main content is as follows:
126
127```
128genext2fs -B ${blocks} -b ${block_size} -d boot_linux -i 8192 -U boot_linux.img
129```
130
131For details about modification for calling **make-boot.sh**, see the following:
132
133https://gitee.com/openharmony/build/pulls/569/files
134
135### INIT Configuration
136
137For details about the init configuration, see the [specifications of the startup subsystem](https://gitee.com/openharmony/docs/blob/master/en/readme/startup.md).
138
139## **Audio**
140
141### Overall structure of the RK3568 audio module
142
143![dayu200-audio-01.png](figures/dayu200/dayu200-audio-01.png)
144
145### Introduction to ADM Adaptation Solution
146
147#### ADM framework adaptation of the RK3568 platform
148
149![](figures/dayu200/dayu200-audio-02.png)
150
1511. ADM Drivers adapter
152
153   Register the Codec/DMA/I2S driver so that the ADM can load the driver node. Register the API functions for the interaction between the ADM and drivers.
154
1552. ADM Drivers impl
156
157   Implement the ADM Drivers adapter API function, obtain configuration information such as **Codec_config.hcs/dai_config.hcs**, and register the information with the corresponding device.
158
1593. Linux Drivers
160
161   You can use **ADM Drivers impl** to complete end-to-end driver configuration based on the hardware manual. It can also use the native Linux driver implementation and APIs to reduce your workload.
162
163#### Directory Structure
164
165```
166./device/board/hihope/rk3568/audio_drivers
167├── codec
168│   └── rk809_codec
169│       ├── include
170│       │   ├── rk809_codec_impl.h
171│       │   └── rk817_codec.h
172│       └── src
173│           ├── rk809_codec_adapter.c
174│           ├── rk809_codec_linux_driver.c
175│           └── rk809_codec_ops.c
176├── dai
177│   ├── include
178│   │   ├── rk3568_dai_linux.h
179│   │   └── rk3568_dai_ops.h
180│   └── src
181│       ├── rk3568_dai_adapter.c
182│       ├── rk3568_dai_linux_driver.c
183│       └── rk3568_dai_ops.c
184├── dsp
185│   ├── include
186│   │   └── rk3568_dsp_ops.h
187│   └── src
188│       ├── rk3568_dsp_adapter.c
189│       └── rk3568_dsp_ops.c
190├── include
191│   ├── audio_device_log.h
192│   └── rk3568_audio_common.h
193└── soc
194    ├── include
195    │   └── rk3568_dma_ops.h
196    └── src
197        ├── rk3568_dma_adapter.c
198        └── rk3568_dma_ops.c
199```
200
201### Detailed Process of Adapting RK3568 to ADM
202
203#### Audio Framework Sorting
204
205Sort out the audio structure of the target platform and specify the data stream and control stream path.
206
2071. For the RK3568 platform, the audio structure is relatively simple. For details, see the overall audio structure of the RK3568 platform. The Codec functions as an independent device. The I2C controls the device, and the I2S implements the interaction between the codec device and the CPU.
2082. Sort out the hardware information such as the I2S channel ID, corresponding pin ID, I2C channel ID, and address based on the schematic diagram.
2093. Obtain the datasheet corresponding to the codec and the datasheet of the RK3568 platform (including the introduction to the registers such as the I2S and DMA channels).
210
211#### ADM Structure
212
213The following figure shows the ADM structure. Audio Peripheral Drivers and Platform Drivers are required for platform adaptation.
214
215![dayu200-audio-03.png](figures/dayu200/dayu200-audio-03.png)
216
217Based on the audio structure analysis in step 1, Audio Peripheral Drivers contain the RK809 driver, and Platform Drivers contain the DMA driver and I2S driver.
218
219| Driver to Adapt| ADM Module| API File Path                                        |
220| -------------- | ----------- | ---------------------------------------------------- |
221| RK809 driver     | Accessory   | drivers/framework/include/audio/audio_accessory_if.h |
222| DMA driver       | platform    | drivers/framework/include/audio/audio_platform_if.h  |
223| I2S driver       | DAI         | drivers/framework/include/audio/audio_dai_if.h.h     |
224
225#### Driver Code Framework Setup
226
227##### Configuring the HCS File
228
229Register the driver node under **audio** in the **device_info.hcs** file.
230
231```c
232        audio :: host {
233            hostName = "audio_host";
234            priority = 60;
235            device_dai0 :: device {
236                device0 :: deviceNode {
237                    policy = 1;
238                    priority = 50;
239                    preload = 0;
240                    permission = 0666;
241                    moduleName = "DAI_RK3568";
242                    serviceName = "dai_service";
243                    deviceMatchAttr = "hdf_dai_driver";
244                }
245            }
246            device_codec :: device {
247                device0 :: deviceNode {
248                    policy = 1;
249                    priority = 50;
250                    preload = 0;
251                    permission = 0666;
252                    moduleName = "CODEC_RK809";
253                    serviceName = "codec_service_0";
254                    deviceMatchAttr = "hdf_codec_driver";
255                }
256            }
257            device_codec_ex :: device {
258                device0 :: deviceNode {
259                    policy = 1;
260                    priority = 50;
261                    preload = 0;
262                    permission = 0666;
263                    moduleName = "CODEC_RK817";
264                    serviceName = "codec_service_1";
265                    deviceMatchAttr = "hdf_codec_driver_ex";
266                }
267            }
268            device_dsp :: device {
269                device0 :: deviceNode {
270                    policy = 1;
271                    priority = 50;
272                    preload = 0;
273                    permission = 0666;
274                    moduleName = "DSP_RK3568";
275                    serviceName = "dsp_service_0";
276                    deviceMatchAttr = "hdf_dsp_driver";
277                }
278            }
279            device_dma :: device {
280                device0 :: deviceNode {
281                    policy = 1;
282                    priority = 50;
283                    preload = 0;
284                    permission = 0666;
285                    moduleName = "DMA_RK3568";
286                    serviceName = "dma_service_0";
287                    deviceMatchAttr = "hdf_dma_driver";
288                }
289            }
290            ......
291        }
292
293```
294
295Select the Codec node or Accessory node based on the connected device, and configure the private attributes (including the start address of the register and the address of the related control register) corresponding to the device. **Codec_config.hcs** and **DAI_config.hcs** are involved.
296
297For details about the configuration, see the HCS configuration section and **audio_parse** module code of the ADM framework in [Audio](https://gitee.com/openharmony/docs/blob/master/en/device-dev/driver/driver-peripherals-audio-des.md).
298
299##### Codec/Accessory Module
300
3011. Register the driver with the HDF framework. The code snippet is as follows. The **moduleName** is the same as that in the HCS file.
302
303   ```
304   struct HdfDriverEntry g_codecDriverEntry = {
305      .moduleVersion = 1,
306      .moduleName = "CODEC_HI3516",
307      .Bind = CodecDriverBind,
308      .Init = CodecDriverInit,
309      .Release = CodecDriverRelease,
310   };
311   HDF_INIT(g_codecDriverEntry);
312   ```
313
3142. Fill the Codec module with:
315
316   **g_codecData**: operation function set and private data set of the codec device.
317
318   **g_codecDaiDeviceOps**: codec DAI device operation function set, including APIs for starting transmission and setting parameters.
319
320   **g_codecDaiData**: operation function set and private data set of the digital audio API of the codec.
321
3223. Implement the bind, init, and release functions.
323
3244. Verification
325
326   Add debug logs to the bind and init functions, compile the version, and obtain system logs.
327
328   ```
329   [    1.548624] [E/"rk809_codec_adapter"]  [Rk809DriverBind][line:258]: enter
330   [    1.548635] [E/"rk809_codec_adapter"]  [Rk809DriverBind][line:260]: success
331   [    1.548655] [E/"rk809_codec_adapter"]  [Rk809DriverInit][line:270]: enter
332   [    1.549050] [E/"rk809_codec_adapter"]  [GetServiceName][line:226]: enter
333   [    1.549061] [E/"rk809_codec_adapter"]  [GetServiceName][line:250]: success
334   [    1.549072] [E/"rk809_codec_adapter"]  [Rk809DriverInit][line:316]: g_chip->accessory.drvAccessoryName = codec_service_1
335   [    1.549085] [E/audio_core]  [AudioSocRegisterDai][line:86]: Register [accessory_dai] success.
336   [    1.549096] [E/audio_core]  [AudioRegisterAccessory][line:120]: Register [codec_service_1] success.
337   [    1.549107] [E/"rk809_codec_adapter"]  [Rk809DriverInit][line:323]: success!
338   ```
339
340
341
342##### DAI Module
343
3441. Register the I2S driver with the HDF framework. The code snippet is as follows. The **moduleName** is the same as that in the HCS file.
345
346   ```c
347   struct HdfDriverEntry g_daiDriverEntry = {
348       .moduleVersion = 1,
349       .moduleName = "DAI_RK3568",
350       .Bind = DaiDriverBind,
351       .Init = DaiDriverInit,
352       .Release = DaiDriverRelease,
353   };
354   HDF_INIT(g_daiDriverEntry);
355   ```
356
3572. Fill the DAI module with:
358
359   ```c
360   struct AudioDaiOps g_daiDeviceOps = {
361       .Startup = Rk3568DaiStartup,
362       .HwParams = Rk3568DaiHwParams,
363       .Trigger = Rk3568NormalTrigger,
364   };
365
366   struct DaiData g_daiData = {
367       .Read = Rk3568DeviceReadReg,
368       .Write = Rk3568DeviceWriteReg,
369       .DaiInit = Rk3568DaiDeviceInit,
370       .ops = &g_daiDeviceOps,
371   };
372   ```
373
3743. Implement the bind, init, and release functions.
375
3764. Verification
377
378   Add debug logs to the bind and init functions, compile the version, and obtain system logs.
379
380   ```
381   [    1.549193] [I/device_node] launch devnode dai_service
382   [    1.549204] [E/HDF_LOG_TAG]  [DaiDriverBind][line:38]: entry!
383   [    1.549216] [E/HDF_LOG_TAG]  [DaiDriverBind][line:55]: success!
384   [    1.549504] [E/audio_core]  [AudioSocRegisterDai][line:86]: Register [dai_service] success.
385   [    1.549515] [E/HDF_LOG_TAG]  [DaiDriverInit][line:116]: success.
386   ```
387
388##### Platform Module
389
3901. Register the DMA driver with the HDF framework. The code snippet is as follows. The **moduleName** is the same as that in the HCS file.
391
392   ```
393   struct HdfDriverEntry g_platformDriverEntry = {
394       .moduleVersion = 1,
395       .moduleName = "DMA_RK3568",
396       .Bind = PlatformDriverBind,
397       .Init = PlatformDriverInit,
398       .Release = PlatformDriverRelease,
399   };
400   HDF_INIT(g_platformDriverEntry);
401   ```
402
4032. Fill the DMA module with:
404
405   ```c
406   struct AudioDmaOps g_dmaDeviceOps = {
407       .DmaBufAlloc = Rk3568DmaBufAlloc,
408       .DmaBufFree = Rk3568DmaBufFree,
409       .DmaRequestChannel = Rk3568DmaRequestChannel,
410       .DmaConfigChannel = Rk3568DmaConfigChannel,
411       .DmaPrep = Rk3568DmaPrep,
412       .DmaSubmit = Rk3568DmaSubmit,
413       .DmaPending = Rk3568DmaPending,
414       .DmaPause = Rk3568DmaPause,
415       .DmaResume = Rk3568DmaResume,
416       .DmaPointer = Rk3568PcmPointer,
417   };
418
419   struct PlatformData g_platformData = {
420       .PlatformInit = AudioDmaDeviceInit,
421       .ops = &g_dmaDeviceOps,
422   };
423   ```
424
4253. Implement the bind, init, and release functions.
426
4274. Verification
428
429   Add debug logs to the bind and init functions, compile the version, and obtain system logs.
430
431   ```
432   [    1.548469] [E/rk3568_platform_adapter]  [PlatformDriverBind][line:42]: entry!
433   [    1.548481] [E/rk3568_platform_adapter]  [PlatformDriverBind][line:58]: success!
434   [    1.548492] [E/rk3568_platform_adapter]  [PlatformDriverInit][line:100]: entry.
435   [    1.548504] [E/rk3568_platform_adapter]  [PlatformGetServiceName][line:67]: entry!
436   [    1.548515] [E/rk3568_platform_adapter]  [PlatformGetServiceName][line:91]: success!
437   [    1.548528] [E/audio_core]  [AudioSocRegisterPlatform][line:63]: Register [dma_service_0] success.
438   [    1.548536] [E/rk3568_platform_adapter]  [PlatformDriverInit][line:119]: success.
439   ```
440
441#### Driver Adaptation
442
443##### Codec/Accessory Module
444
4451. Read the DTS file to obtain the corresponding device node, and use the native driver registration function of Linux to obtain the corresponding device.
446
447   ```
448   static int rk817_platform_probe(struct platform_device *pdev) {
449       rk817_pdev = pdev;
450       dev_info(&pdev->dev, "got rk817-codec platform_device");
451       return 0;
452   }
453
454   static struct platform_driver rk817_codec_driver = {
455   	.driver = {
456   		   .name = "rk817-codec",                     // codec node in dts file
457   		   .of_match_table = rk817_codec_dt_ids,
458   		   },
459   	.probe = rk817_platform_probe,
460   	.remove = rk817_platform_remove,
461   };
462   ```
463
4642. Encapsulate the functions for reading and writing registers.
465   Use the **regmap** function of Linux based on the obtained device. You do not need to obtain the base address of the module.
466   Obtain the regmap code snippet of RK817.
467
468   ```
469   g_chip = devm_kzalloc(&rk817_pdev->dev, sizeof(struct Rk809ChipData), GFP_KERNEL);
470       if (!g_chip) {
471           AUDIO_DEVICE_LOG_ERR("no memory");
472           return HDF_ERR_MALLOC_FAIL;
473       }
474       g_chip->pdev = rk817_pdev;
475
476       struct rk808 *rk808 = dev_get_drvdata(g_chip->pdev->dev.parent);
477       if (!rk808) {
478           AUDIO_DEVICE_LOG_ERR("%s: rk808 is NULL\n", __func__);
479           ret = HDF_FAILURE;
480           RK809ChipRelease();
481   		return ret;
482       }
483       g_chip->regmap = devm_regmap_init_i2c(rk808->i2c,
484   		&rk817_codec_regmap_config);
485       if (IS_ERR(g_chip->regmap)) {
486           AUDIO_DEVICE_LOG_ERR("failed to allocate regmap: %ld\n", PTR_ERR(g_chip->regmap));
487           RK809ChipRelease();
488   		return ret;
489       }
490   ```
491
492   Code snippet of read and write functions of the register
493
494   ```
495   int32_t Rk809DeviceRegRead(uint32_t reg, uint32_t *val)
496     {
497         if (regmap_read(g_chip->regmap, reg, val)) {
498             AUDIO_DRIVER_LOG_ERR("read register fail: [%04x]", reg);
499             return HDF_FAILURE;
500         }
501
502         return HDF_SUCCESS;
503     }
504
505     int32_t Rk809DeviceRegWrite(uint32_t reg, uint32_t value) {
506         if (regmap_write(g_chip->regmap, reg, value)) {
507             AUDIO_DRIVER_LOG_ERR("write register fail: [%04x] = %04x", reg, value);
508             return HDF_FAILURE;
509         }
510
511         return HDF_SUCCESS;
512     }
513
514     int32_t Rk809DeviceRegUpdatebits(uint32_t reg, uint32_t mask, uint32_t value) {
515         if (regmap_update_bits(g_chip->regmap, reg, mask, value)) {
516             AUDIO_DRIVER_LOG_ERR("update register bits fail: [%04x] = %04x", reg, value);
517             return HDF_FAILURE;
518         }
519
520         return HDF_SUCCESS;
521     }
522   ```
523
5243. Define the register Initialization function.
525
526   The **regmap** function of Linux is used. Therefore, you need to define the **RegDefaultInit** function and read the initSeqConfig register and value in the HCS for configurations.
527
528   RK809RegDefaultInit code snippet
529
530   ```c
531   int32_t RK809RegDefaultInit(struct AudioRegCfgGroupNode **regCfgGroup)
532   {
533     int32_t i;
534     struct AudioAddrConfig *regAttr = NULL;
535
536     if (regCfgGroup == NULL || regCfgGroup[AUDIO_INIT_GROUP] == NULL ||
537        regCfgGroup[AUDIO_INIT_GROUP]->addrCfgItem == NULL || regCfgGroup[AUDIO_INIT_GROUP]->itemNum <= 0) {
538        AUDIO_DEVICE_LOG_ERR("input invalid parameter.");
539
540        return HDF_ERR_INVALID_PARAM;
541     }
542
543     regAttr = regCfgGroup[AUDIO_INIT_GROUP]->addrCfgItem;
544
545     for (i = 0; i < regCfgGroup[AUDIO_INIT_GROUP]->itemNum; i++) {
546        Rk809DeviceRegWrite(regAttr[i].addr, regAttr[i].value);
547     }
548
549     return HDF_SUCCESS;
550   }
551   ```
552
5534. Encapsulate the read and write functions of the control API.
554
555   Set the control read/write functions to **RK809CodecReadReg** and **RK809CodecWriteReg**.
556
557   ```c
558   struct CodecData g_rk809Data = {
559       .Init = Rk809DeviceInit,
560       .Read = RK809CodecReadReg,
561       .Write = RK809CodecWriteReg,
562   };
563
564   struct AudioDaiOps g_rk809DaiDeviceOps = {
565       .Startup = Rk809DaiStartup,
566       .HwParams = Rk809DaiHwParams,
567   	.Trigger = RK809NormalTrigger,
568   };
569
570   struct DaiData g_rk809DaiData = {
571       .DaiInit = Rk809DaiDeviceInit,
572       .ops = &g_rk809DaiDeviceOps,
573   };
574   ```
575
576   Encapsulate the read and write functions of the control API.
577
578   The original read/write prototype involves three parameters (**unsigned long virtualAddress**, **uint32_t reg**, and **uint32_t *val**). The virtual address is not required. Therefore, you only need to encapsulate one API as follows:
579
580   ```c
581   int32_t RK809CodecReadReg(unsigned long virtualAddress,uint32_t reg, uint32_t *val)
582   {
583       if (val == NULL) {
584           AUDIO_DRIVER_LOG_ERR("param val is null.");
585           return HDF_FAILURE;
586       }
587       if (Rk809DeviceRegRead(reg, val)) {
588           AUDIO_DRIVER_LOG_ERR("read register fail: [%04x]", reg);
589           return HDF_FAILURE;
590       }
591       ADM_LOG_ERR("read reg 0x[%02x] = 0x[%02x]",reg,*val);
592       return HDF_SUCCESS;
593   }
594
595   int32_t RK809CodecWriteReg(unsigned long virtualAddress,uint32_t reg, uint32_t value)
596   {
597       if (Rk809DeviceRegWrite(reg, value)) {
598           AUDIO_DRIVER_LOG_ERR("write register fail: [%04x] = %04x", reg, value);
599           return HDF_FAILURE;
600       }
601       ADM_LOG_ERR("write reg 0x[%02x] = 0x[%02x]",reg,value);
602       return HDF_SUCCESS;
603   }
604   ```
605
6065. For other OPS functions:
607
608  - **Rk809DeviceInit**: Read the HCS file, initialize the codec register, and add the corresponding control configuration (/* reg, rreg, shift, rshift, min, max, mask, invert, value */) to kcontrol to facilitate dispatch control.
609  - **Rk809DaiStartup**: Read the HCS file, and configure the control register of the codec/accessory.
610  - **Rk809DaiHwParams**: Configure the corresponding register based on the audio attributes (such as the sampling rate, format, and channel) delivered by the HAL.
611  - **RK809NormalTrigger**: Operate the corresponding register based on the operation command code delivered by the HAL to start or stop the codec and switch between recording and playing.
612
613##### DAI (i2s) Module
614
6151. Read and write registers.
616
617   The idea is the same as that of the Codec module. Read the Linux DTS file and use the **regmap** function of Linux to read and write registers.
618
619      ```c
620      int32_t Rk3568DeviceReadReg(unsigned long regBase, uint32_t reg, uint32_t *val)
621       {
622           AUDIO_DEVICE_LOG_ERR("entry");
623           (void)regBase;
624           struct device_node *dmaOfNode = of_find_node_by_path("/i2s@fe410000");
625           if(dmaOfNode == NULL) {
626               AUDIO_DEVICE_LOG_ERR("of_node is NULL.");
627           }
628           struct platform_device *platformdev = of_find_device_by_node(dmaOfNode);
629           struct rk3568_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(&platformdev->dev);
630
631           (void)regBase;
632           if (regmap_read(i2s_tdm->regmap, reg, val)) {
633               AUDIO_DEVICE_LOG_ERR("read register fail: [%04x]", reg);
634               return HDF_FAILURE;
635           }
636           return HDF_SUCCESS;
637       }
638
639       int32_t Rk3568DeviceWriteReg(unsigned long regBase, uint32_t reg, uint32_t value)
640       {
641           AUDIO_DEVICE_LOG_ERR("entry");
642           (void)regBase;
643           struct device_node *dmaOfNode = of_find_node_by_path("/i2s@fe410000");
644           if(dmaOfNode == NULL) {
645               AUDIO_DEVICE_LOG_ERR("of_node is NULL.");
646           }
647           struct platform_device *platformdev = of_find_device_by_node(dmaOfNode);
648           struct rk3568_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(&platformdev->dev);
649           if (regmap_write(i2s_tdm->regmap, reg, value)) {
650               AUDIO_DEVICE_LOG_ERR("write register fail: [%04x] = %04x", reg, value);
651               return HDF_FAILURE;
652           }
653           return HDF_SUCCESS;
654       }
655      ```
656
6572. For other OPS functions:
658
659  - Rk3568DaiDeviceInit
660
661    Original framework, which reads the **DAI_config.hcs** parameter list and works with HwParams to set parameters.
662
663
664  - Rk3568DaiHwParams
665
666    Configure the I2S MCLK/BCLK/LRCLK clocks.
667
668
669    1. Calculate the MCLK based on different sampling rates.
670
671       ```c
672           int32_t RK3568I2sTdmSetSysClk(struct rk3568_i2s_tdm_dev *i2s_tdm, const struct AudioPcmHwParams *param)
673           {
674               /* Put set mclk rate into rockchip_i2s_tdm_set_mclk() */
675               uint32_t sampleRate = param->rate;
676               uint32_t mclk_parent_freq = 0;
677               switch (sampleRate) {
678                   case AUDIO_DEVICE_SAMPLE_RATE_8000:
679                   case AUDIO_DEVICE_SAMPLE_RATE_16000:
680                   case AUDIO_DEVICE_SAMPLE_RATE_24000:
681                   case AUDIO_DEVICE_SAMPLE_RATE_32000:
682                   case AUDIO_DEVICE_SAMPLE_RATE_48000:
683                   case AUDIO_DEVICE_SAMPLE_RATE_64000:
684                   case AUDIO_DEVICE_SAMPLE_RATE_96000:
685                   mclk_parent_freq = i2s_tdm->bclk_fs * AUDIO_DEVICE_SAMPLE_RATE_192000;
686                   break;
687                   case AUDIO_DEVICE_SAMPLE_RATE_11025:
688                   case AUDIO_DEVICE_SAMPLE_RATE_22050:
689                   case AUDIO_DEVICE_SAMPLE_RATE_44100:
690
691                   mclk_parent_freq = i2s_tdm->bclk_fs * AUDIO_DEVICE_SAMPLE_RATE_176400;
692                   break;
693                   default:
694                   AUDIO_DEVICE_LOG_ERR("Invalid LRCK freq: %u Hz\n", sampleRate);
695                       return HDF_FAILURE;
696               }
697               i2s_tdm->mclk_tx_freq = mclk_parent_freq;
698               i2s_tdm->mclk_rx_freq = mclk_parent_freq;
699
700               return HDF_SUCCESS;
701           }
702       ```
703
704    2. Calculate the BCLK/LRclk frequency division coefficient based on the obtained MCLK.
705
706  - Rk3568NormalTrigger
707
708    Complete a series of configurations based on the input and output types and commands (start/stop/pause/resume).
709
710
711    1. Start and stop the MCLK.
712    2. Start and stop DMA transfer.
713    3. Start and stop transmission.
714      See the code for detailed implementation, and refer to the API functions of the native Linux I2S driver.
715
716    ```c
717        // Start or restore the process.
718        if (streamType == AUDIO_RENDER_STREAM) {
719            clk_prepare_enable(i2s_tdm->mclk_tx);
720            regmap_update_bits(i2s_tdm->regmap, I2S_DMACR,
721                       I2S_DMACR_TDE_ENABLE,
722                       I2S_DMACR_TDE_ENABLE);
723        } else {
724            clk_prepare_enable(i2s_tdm->mclk_rx);
725            regmap_update_bits(i2s_tdm->regmap, I2S_DMACR,
726                       I2S_DMACR_RDE_ENABLE,
727                       I2S_DMACR_RDE_ENABLE);
728            if (regmap_read(i2s_tdm->regmap, I2S_DMACR, &val)) {
729                AUDIO_DEVICE_LOG_ERR("read register fail: [%04x]", I2S_DMACR);
730                return ;
731                }
732            AUDIO_DEVICE_LOG_ERR("i2s reg: 0x%x = 0x%x ", I2S_DMACR, val);
733        }
734
735        if (atomic_inc_return(&i2s_tdm->refcount) == 1) {
736            regmap_update_bits(i2s_tdm->regmap, I2S_XFER,
737                       I2S_XFER_TXS_START |
738                       I2S_XFER_RXS_START,
739                       I2S_XFER_TXS_START |
740                       I2S_XFER_RXS_START);
741            if (regmap_read(i2s_tdm->regmap, I2S_XFER, &val)) {
742                AUDIO_DEVICE_LOG_ERR("read register fail: [%04x]", I2S_XFER);
743                return ;
744                }
745            AUDIO_DEVICE_LOG_ERR("i2s reg: 0x%x = 0x%x ", I2S_XFER, val);
746        }
747    ```
748##### Platform (DMA) Module
749
750For other OPS functions:
751
7521. Rk3568DmaBufAlloc/Rk3568DmaBufFree
753
754    Obtain the DMA device node. Use the system function **dma_alloc_wc** or **dma_free_wc** to apply for or release the DMA virtual memory and physical memory by referring to the method of obtaining the I2S device.
755
7562. Rk3568DmaRequestChannel
757
758    Use the native Linux DMA API function to obtain the DMA transfer channel **dma_request_slave_channel**.
759
760   ```
761   dmaRtd->dmaChn[streamType] = dma_request_slave_channel(dmaDevice, dmaChannelNames[streamType]);
762   ```
763
7643. Rk3568DmaConfigChannel
765
766   ```
767      // Set channel parameters.
768      // Set voice playing channel parameters.
769      slave_config.direction = DMA_MEM_TO_DEV;
770      slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
771      slave_config.dst_addr = I2S1_ADDR + I2S_TXDR;
772      slave_config.dst_maxburst = 8;
773      // Set recording channel parameters.
774      slave_config.direction = DMA_DEV_TO_MEM;
775      slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
776      slave_config.src_addr = I2S1_ADDR + I2S_RXDR;
777      slave_config.src_maxburst = 8;
778
779      // Use the native Linux DMA API function to configure the DMA channel.
780      ret = dmaengine_slave_config(dmaChan, &slave_config);
781      if (ret != 0) {
782          AUDIO_DEVICE_LOG_ERR("dmaengine_slave_config failed");
783          return HDF_FAILURE;
784      }
785   ```
786
7874. Rk3568DmaSubmit/Rk3568DmaPending
788
789      Initialize a periodic DMA transfer descriptor by using the native Linux DMA API function **dmaengine_prep_dma_cyclic**. The **dmaengine_submit** API places the descriptor in the transfer queue, and then calls **dma_async_issue_pending** to start the transfer.
790
7915. Rk3568PcmPointer
792
793      After step 4 is complete, the ADM framework calls Rk3568PcmPointer to cyclically write CirBuf and calculate the pointer.
794
795   ```
796
797      dma_chn = dmaRtd->dmaChn[DMA_TX_CHANNEL];
798      buf_size = data->renderBufInfo.cirBufSize;
799      dmaengine_tx_status(dma_chn, dmaRtd->cookie[DMA_TX_CHANNEL], &dma_state);
800      if (dma_state.residue) {
801          currentPointer = buf_size - dma_state.residue;
802          *pointer = BytesToFrames(data->pcmInfo.frameSize, currentPointer);
803      } else {
804          *pointer = 0;
805      }
806   ```
807
8086. Rk3568DmaPause
809
810   Use the native Linux DMA API function **dmaengine_terminate_async** to stop DMA transfer.
811
812   ```
813    dmaengine_terminate_async(dmaChan);
814   ```
815
8167. Rk3568DmaResume
817
818   Restart DMA transfer. You can perform operations related to **Rk3568DmaSubmit/Rk3568DmaPending**.
819
820##### FAQs for Adaptation
821
8221. After the audio plays for a period of time, the audio stops playing and there is a sharp and small sound.
823        Cause: After the playback stops, the components related to the codec are not powered off.
824        Solution: Register the **trigger** function of the codec. When the received command is **Stop**, power off the codec.
825
8262. After the audio plays for a period of time and stops, no sound can be heard when the playback is resumed.
827         Cause: The **PAUSE** API function of the DMA driver does not stop DMA transfer.
828         Solution: When the playback stops, the **PAUSE** function of the DMA is not used. Instead, the DAM transfer stop API is used. Accordingly, the service logic of the resume function is equivalent to restarting the DMA transfer. You can perform operations related to **Rk3568DmaSubmit/Rk3568DmaPending**.
829
8303. Noise occurs during playback.
831          Cause: The pointer position during DMA data transfer is incorrect.
832          Solution: The return value of the **Rk3568PcmPointer** function is the memory location for DMA transfer, which is calculated based on the difference between **buf** and **dma_state.residue**.
833
8344. The audio can be played, but the MCLK pin does not have clock signals.
835           Cause: The pin-ctrl in the DTS file is not configured with the MCLK pin.
836           Solution: Modify the DTS file.
837
838### Camera
839
840**Basic Concepts**
841
842The OpenHarmony camera driver model implements the HDI and the camera pipeline model to manage camera devices. The basic concepts of each layer are as follows:
843
8441. HDI implementation layer: implements standard device APIs of OHOS cameras.
845
8462. Framework layer: connects to the HDI implementation layer for control instruction and stream transfer, establishes data channels, and manages camera devices.
847
8483. Adaptation layer: shields the differences between bottom-layer chips and OSs for multi-platform adaptation.
849
850### Camera Driver Framework
851
852#### Source Code Framework
853
854The camera driver framework is stored in **drivers_peripheral**, and the source code directory is **drivers/peripheral/camera**.
855
856```
857|-- README_zh.md
858|-- figures
859|  -- logic-view-of-modules-related-to-this-repository_zh.png
860|-- hal
861|  |-- BUILD.gn               # Entry for building the camera driver framework
862|  |-- adapter                 # Platform adaptation layer
863|  |-- buffer_manager
864|  |-- camera.gni               # Global variables used by the component
865|  |-- device_manager
866|  |-- hdi_impl
867|  |-- include
868|  |-- init                   #demo sample
869|  |-- pipeline_core
870|  |-- test                   # Test code
871|  |-- utils
872|-- hal_c                    # Dedicated C API for HiSilicon
873|  |-- BUILD.gn
874|  |-- camera.gni
875|  |-- hdi_cif
876|  |-- include
877|-- interfaces                  # HDI APIs
878  |-- hdi_ipc
879|-- hdi_passthrough
880   |-- include
881```
882
883The camera .hcs file is configurable for each chipset. Therefore, it is placed in the chipset-related repository. The following takes RK3568 as an example. The repository name is **vendor_hihope**, and the source code directory is **vendor/hihope/rk3568/hdf_config/uhdf/camera**.
884
885    ├── hdi_impl
886    │   └── camera_host_config.hcs
887    └── pipeline_core
888        ├── config.hcs
889        ├── ipp_algo_config.hcs
890        └── params.hcs
891The code repository related to the camera chipset of RK3568 is **device_hihope**. Path: device/board/hihope/rk3568/camera/
892```
893├── BUILD.gn
894├── demo
895│   └── include
896│       └── project_camera_demo.h
897├── device_manager
898│   ├── BUILD.gn
899│   ├── include
900│   │   ├── imx600.h
901│   │   ├── project_hardware.h
902│   │   └── rkispv5.h
903│   └── src
904│       ├── imx600.cpp
905│       └── rkispv5.cpp
906├── driver_adapter
907│   └── test
908│       ├── BUILD.gn
909│       ├── unittest
910│       │   ├── include
911│       │   │   └── utest_v4l2_dev.h
912│       │   └── src
913│       │       └── utest_v4l2_dev.cpp
914│       └── v4l2_test
915│           └── include
916│               └── project_v4l2_main.h
917└── pipeline_core
918    ├── BUILD.gn
919    └── src
920        ├── ipp_algo_example
921        │   └── ipp_algo_example.c
922        └── node
923            ├── rk_codec_node.cpp
924            └── rk_codec_node.h
925```
926  ####  Camera Driver Framework Configuration
927
928Path of the RK3568 configuration file: "vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs".
929
930For other platforms, refer to the RK3568 adaptation.
931
932```
933        hdi_server :: host {
934            hostName = "camera_host";
935            priority = 50;
936            caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"];
937            camera_device :: device {
938                 device0 :: deviceNode {
939                     policy = 2;
940                     priority = 100;
941                     moduleName = "libcamera_hdi_impl.z.so";
942                     serviceName = "camera_service";
943                 }
944             }
945            ...
946        }
947```
948
949Parameter description:
950
951**Host**: A host node is an independent process. If an independent process is required, add a host node.
952
953**Policy**: service publish policy. Set this parameter to **2** for the HDI service.
954
955**moduleName**: name of the driver implementation library.
956
957**serviceName**: service name, which must be globally unique.
958
959Entry for implementing the Camera_host driver
960
961File path: drivers/peripheral/camera/interfaces/hdi_ipc/server/src/camera_host_driver.cpp
962
963Dispatch device service messages.
964
965**cmd Id:** command ID of the request.
966
967**Data:** pointer to other services or I/O requests.
968
969**Reply:** pointer to the content of the returned message.
970
971```
972static int32_t CameraServiceDispatch(struct HdfDeviceIoClient *client, int cmdId,
973    struct HdfSBuf *data, struct HdfSBuf *reply)
974{
975    HdfCameraService *hdfCameraService = CONTAINER_OF(client->device->service, HdfCameraService, ioservice);
976      return CameraHostServiceOnRemoteRequest(hdfCameraService->instance, cmdId, data, reply);
977 }
978```
979
980Bind a device service: initializes the device service object and resource object.
981
982```
983int HdfCameraHostDriverBind(HdfDeviceObject *deviceObject)
984{
985    HDF_LOGI("HdfCameraHostDriverBind enter!");
986    if (deviceObject == nullptr) {
987        HDF_LOGE("HdfCameraHostDriverBind: HdfDeviceObject is NULL !");
988        return HDF_FAILURE;
989}
990```
991
992Driver initialization function: detects and initializes the driver.
993
994```
995int HdfCameraHostDriverInit(struct HdfDeviceObject *deviceObject)
996{
997      return HDF_SUCCESS;
998}
999```
1000
1001Driver resource release function: releases the bound device service object.
1002
1003```
1004  void HdfCameraHostDriverRelease(HdfDeviceObject *deviceObject)
1005  {
1006          if (deviceObject == nullptr || deviceObject->service == nullptr) {
1007          HDF_LOGE("%{public}s deviceObject or deviceObject->service  is NULL!", __FUNCTION__);
1008                return;
1009      }
1010          HdfCameraService *hdfCameraService = CONTAINER_OF(deviceObject->service, HdfCameraService, ioservice);
1011      if (hdfCameraService == nullptr) {
1012           HDF_LOGE("%{public}s hdfCameraService is NULL!", __FUNCTION__);
1013           return;
1014       }
1015```
1016
1017Define the driver descriptor: registers the driver code with the driver framework.
1018
1019
1020     struct HdfDriverEntry g_cameraHostDriverEntry = {
1021          .moduleVersion = 1,
1022          .moduleName = "camera_service",
1023          .Bind = HdfCameraHostDriverBind,
1024          .Init = HdfCameraHostDriverInit,
1025          .Release = HdfCameraHostDriverRelease,
1026      };
1027
1028
1029####   Camera Configuration
1030
1031In the camera module, all configuration files use the HCS configuration files supported by the system. The HCS configuration files are converted into HCB files during compilation. The configuration files burnt to the development board are in HCB format. In the code, the HCB files are parsed by using the HCS parsing API, to obtain the information in the configuration file.
1032
1033
1034     hc_gen("build_camera_host_config") {
1035        sources = [ rebase_path(
1036                      "$camera_product_name_path/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs") ]
1037      }
1038
1039      ohos_prebuilt_etc("camera_host_config.hcb") {
1040              deps = [ ":build_camera_host_config" ]
1041        hcs_outputs = get_target_outputs(":build_camera_host_config")
1042              source = hcs_outputs[0]
1043        relative_install_dir = "hdfconfig"
1044              install_images = [ chipset_base_dir ]
1045        subsystem_name = "hdf"
1046              part_name = "camera_device_driver"
1047      }
1048
1049### Camera Adaptation
1050
1051####   New Product Platform Adaptation
1052
1053
1054In the **drivers/peripheral/camera/hal/camera.gni** file, call **product.gni** of different chipsets based on the input **product_company**, **product_name**, and **device_name** during compilation.
1055
1056      if (defined(ohos_lite)) {
1057              import("//build/lite/config/component/lite_component.gni")
1058        import(
1059                  "//device/soc/hisilicon/common/hal/media/camera/hi3516dv300/linux_standard/camera/product.gni")
1060      } else {
1061              import("//build/ohos.gni")
1062        if ("${product_name}" == "ohos-arm64") {
1063                import(
1064              "//drivers/peripheral/camera/hal/adapter/chipset/rpi/rpi3/device/camera/product.gni")
1065              } else if ("${product_name}" == "Hi3516DV300") {
1066          import(
1067                    "//device/soc/hisilicon/common/hal/media/camera/hi3516dv300/linux_standard/camera/product.gni")
1068        } else if ("${product_name}" == "watchos") {
1069                import(
1070              "//device/soc/hisilicon/common/hal/media/camera/hi3516dv300/linux_standard/camera/product.gni")
1071              } else {
1072          import(
1073                    "//device/board/${product_company}/${device_name}/camera/product.gni")
1074        }
1075            }
1076
1077The **product.gni** file in the following path specifies the path for compiling the code related to different chipsets:
1078
1079```
1080 device/${product_company}/${device_name}/camera/
1081```
1082
1083The following is the **product.gni** file content of RK3568:
1084
1085      camera_device_name_path = "//device/board/${product_company}/${device_name}"
1086            is_support_v4l2 = true
1087      if (is_support_v4l2) {
1088              is_support_mpi = false
1089        defines += [ "SUPPORT_V4L2" ]
1090              chipset_build_deps = "$camera_device_name_path/camera/:chipset_build"
1091        camera_device_manager_deps =
1092                  "$camera_device_name_path/camera/src/device_manager:camera_device_manager"
1093        camera_pipeline_core_deps =
1094                  "$camera_device_name_path/camera/src/pipeline_core:camera_pipeline_core"
1095      }
1096
1097Three code compilation paths **chipset_build_deps**, **camera_device_manager_deps**, and **camera_pipeline_core_deps** are specified in **product.gni**. The paths are used in **drivers/peripheral/camera/hal/BUILD.gn**.
1098
1099####  Framework Adaptation
1100
1101![dayu200-camera-01.png](figures/dayu200/dayu200-camera-01.png)
11021103
1104Take V4l2 as an example. The pipeline connection mode is to configure the connection in the HCS configuration file. The data source is called SourceNode, including hardware device control and data stream transfer.
1105 You can determine whether to add the ISPNode as required because the ISPNode and SensorNode can be unified as the SourceNode in many operations. SinkNode is the key point of data transmission in the pipeline. Data is transmitted back to the buffer queue.
1106
1107A node in the pipeline is the abstraction of the hardware/software module. Therefore, the hardware module node needs to control the hardware module. Before controlling the hardware module, you need to obtain the **deviceManager** of the corresponding hardware module and transmit the control command/data buffer through the **deviceManager**, therefore, the **deviceManager** has a v4l2 device manager abstract module, which is used to create the manager and controller of each hardware device, such as sensorManager, IspManager, and sensorController. Therefore, the v4l2 device manager is the general manager of each hardware device.
1108
1109The controller in deviceManager directly interacts with the driver adaptation layer.
1110
1111Based on the preceding description, to adapt a chip platform based on the Linux v4l2 framework, you only need to modify certain modules and HCS configuration file. If the standard v4l2 framework is used, the adapted code can be used. The following describes how to modify the modules.
1112
1113The following directories are added:
1114
1115- **vendor/hihope/rk3568/hdf_config/uhdf/camera/**: HCS configuration file directory of the current chip product.
1116
1117- **device/hihope/rk3568/camera/**: code adaptation directory of the current chip product.
1118
1119- **drivers/peripheral/camera/hal/adapter/platform/v4l2**: common platform code.
1120
1121####  HCS Configuration File Adaptation
1122
1123```
1124  ├── hdi_impl
1125  │   └── camera_host_config.hcs
1126  └── pipeline_core
1127      ├── config.hcs
1128      ├── ipp_algo_config.hcs
1129      └── params.hcs
1130```
1131
1132Take the RK3568 development board as an example. The HCS file must be stored in the corresponding path.
1133
1134```
1135 vendor/${product_company}/${product_name}/ hdf_config/uhdf/camera/
1136```
1137
1138  ```
1139  template ability {
1140    logicCameraId = "lcam001";
1141    physicsCameraIds = [
1142    "CAMERA_FIRST",
1143    "CAMERA_SECOND"
1144    ];
1145  metadata {
1146     aeAvailableAntiBandingModes = [
1147         "OHOS_CONTROL_AE_ANTIBANDING_MODE_OFF",
1148         "OHOS_CONTROL_AE_ANTIBANDING_MODE_50HZ",
1149         "OHOS_CONTROL_AE_ANTIBANDING_MODE_60HZ",
1150         "OHOS_CONTROL_AE_ANTIBANDING_MODE_AUTO"
1151          ];
1152
1153  ```
1154
1155The **camera_host_config.hcs** file under **hdi_impl** contains the physical/logical camera configuration and capability configuration. The physical/logical camera configuration needs to be used in the HAL, and the logical camera and capability configuration need to be reported to the upper layer. Add the capability configuration based on the adapted chip product. The used capability values are key-value pairs, which are defined in **//drivers/peripheral/camera/hal/hdi_impl/include/camera_host/metadata_enum_map.h**.
1156
1157```
1158      normal_preview :: pipeline_spec {
1159      name = "normal_preview";
1160            v4l2_source :: node_spec {
1161          name = "v4l2_source#0";
1162                status = "new";
1163          out_port_0 :: port_spec {
1164                    name = "out0";
1165              peer_port_name = "in0";
1166                    peer_port_node_name = "sink#0";
1167              direction = 1;
1168                    width = 0;
1169              height = 0;
1170                    format = 0;
1171          }
1172            }
1173      sink :: node_spec {
1174                name = "sink#0";
1175          status = "new";
1176                stream_type = "preview";
1177          in_port_0 :: port_spec {
1178                    name = "in0";
1179              peer_port_name = "out0";
1180                    peer_port_node_name = "v4l2_source#0";
1181              direction = 0;
1182                }
1183      }
1184    }
1185```
1186
1187 The **config.hcs** file under **pipeline_core** uses the pipeline connection mode. Nodes of each flow and connection modes are classified by scenario.
1188
1189The preceding is an example of the preview scenario. **normal_preview** is the scenario name, **source** and **sink** are nodes, **source** is the data source, and **sink** is the end. The source is the first node, and the node name is **source#0**. **status** and **in/out_port** indicate the node status and input/output port configurations, respectively.
1190
1191 Take **in_port_0** as an example. **name = "in0"** indicates that the input port is port0, the peer end is the out0 port of the source node, and **direction** indicates whether the source node and the peer node are directly connected. If a new chip is added, you must configure this file based on the actual connection mode.
1192
1193When adding a function node, you need to inherit the **NodeBase** class and register the node in the .cpp file. For details, see the implemented nodes in **//drivers/peripheral/camera/hal/pipeline_core/nodes/src**.
1194
1195
1196     root {
1197      module = "";
1198            template stream_info {
1199          id = 0;
1200                name = "";
1201      }
1202            template scene_info {
1203          id = 0;
1204                name = "";
1205      }
1206            preview :: stream_info {
1207          id = 0;
1208                name = "preview";
1209      }
1210            video :: stream_info {
1211          id = 1;
1212                name = "video";
1213      }
1214
1215
1216The **param.hcs** file defines the scenario, flow type name, and flow ID. In the pipeline, the flow ID is used to identify the flow type. Therefore, you need to add the definition here.
1217
1218####  Chipset and Platform Adaptation
1219
1220The platform contains the platform common code, such as the Linux standard v4l2 adaptation API definition, common nodes adapted the v4l2 framework, and common **device_manager** adapted the v4l2 framework. The directory structure is as follows:
1221
1222      drivers/peripheral/camera/hal/adapter/platform
1223      ├── mpp
1224      │   └── src
1225      │       ├── device_manager
1226      │       └── pipeline_core
1227      └── v4l2
1228          └── src
1229              ├── device_manager
1230              ├── driver_adapter
1231              └── pipeline_core
1232
1233The **v4l2** in the **platform** directory contains **src**. **driver_adapter** in **src** is the standard adaptation API of Linux v4l2. If custom functions are required, you can inherit **driver_adapter**, and implement the custom function APIs in the chipset. If there is no chip custom function, you can directly use the existing **driver_adapter**.
1234
1235Nodes in the **platform** directory are hardware modules **v4l2_source_node** and **uvc_node** implemented based on the Linux v4l2 standard. The **uvc_node** is used for USB hot swap devices and is also a standard Linux API and can be directly used. The following shows the API declaration header file of **v4l2_source_node**.
1236
1237
1238     namespace OHOS::Camera {
1239      class V4L2SourceNode : public SourceNode {
1240            public:
1241          V4L2SourceNode(const std::string& name, const std::string& type);
1242                ~V4L2SourceNode() override;
1243          RetCode Init(const int32_t streamId) override;
1244                RetCode Start(const int32_t streamId) override;
1245          RetCode Flush(const int32_t streamId) override;
1246                RetCode Stop(const int32_t streamId) override;
1247          RetCode GetDeviceController();
1248                void SetBufferCallback() override;
1249          RetCode ProvideBuffers(std::shared_ptr\<FrameSpec> frameSpec) override;
1250
1251      private:
1252                std::mutex                              requestLock_;
1253          std::map<int32_t, std::list<int32_t>>   captureRequests_ = {};
1254                std::shared_ptr\<SensorController>       sensorController_ = nullptr;
1255          std::shared_ptr\<IDeviceManager>     deviceManager_ = nullptr;
1256            };
1257      } // namespace OHOS::Camera
1258
1259 **Init**: initializes modules.
1260
1261**Start**: enables functions, such as start stream.
1262
1263 **Stop**: disables functions.
1264
1265 **GetDeviceController** is the controller API for obtaining the deviceManager.
1266
1267Chipset is the code related to a specific chip platform, for example, the RK3568 development board. The **device_manager** directory stores the configuration files of the sensors adapted the development board. The **pipeline_core** directory can store pipeline nodes added to meet specific requirements.
1268
1269```
1270 device/board/hihope/rk3568/camera
1271  ├── BUILD.gn
1272  ├── camera_demo
1273  │   └── project_camera_demo.h
1274  ├── include
1275  │   └── device_manager
1276  ├── product.gni
1277  └── src
1278      ├── device_manager
1279      ├── driver_adapter
1280      └── pipeline_core
1281```
1282
1283The **device/board/hihope/rk3568/camera/** directory contains **include** and **src**. In **camera_demo** and **src**, **device ­manager** contains the sensor files adapted the chipset, works with the device management directory of **device manager** on the platform, and connects to the pipeline to implement platform-specific hardware processing APIs, data buffer delivery and reporting, and metadata interaction.
1284
1285The following figure shows the implementation of **device_manager**. The pipeline controls and manages each hardware module. First, you need to obtain the manager of the corresponding device, and obtain the corresponding controller through the manager. The controller interacts with the corresponding driver.
1286
1287 ![img](figures/dayu200/dayu200-camera-02.png)
1288
1289Key APIs that need to be implemented in DeviceManager:
1290
1291```
1292      class SensorController : public IController {
1293      public:
1294          SensorController();
1295          explicit SensorController(std::string hardwareName);
1296          virtual ~SensorController();
1297          RetCode Init();
1298          RetCode PowerUp();
1299          RetCode PowerDown();
1300          RetCode Configure(std::shared_ptr<CameraStandard::CameraMetadata> meta);
1301          RetCode Start(int buffCont, DeviceFormat& format);
1302          RetCode Stop();
1303          RetCode SendFrameBuffer(std::shared_ptr<FrameSpec> buffer);
1304          void SetNodeCallBack(const NodeBufferCb cb);
1305          void SetMetaDataCallBack(const MetaDataCb cb);
1306          void BufferCallback(std::shared_ptr<FrameSpec> buffer);
1307          void SetAbilityMetaDataTag(std::vector<int32_t> abilityMetaDataTag);
1308    }
1309```
1310
1311   **PowerUp** is used for power-on. You can call this API to power on a device for OpenCamera.
1312   **PowerDown** is used for power-off. You can call this API to power off a device for CloseCamera.
1313   The **Configures** API is used to deliver metadata. If metadata parameters need to be set on hardware devices, this API can be used to parse and deliver metadata parameters.
1314   The **Start** API is used to enable the hardware module, and is called when each node in the pipeline is enabled. You can define the implementation as required. For example, the start operation of the sensor can be implemented here.
1315   **Stop** and **Start** are reverse operations. You can call **Stop** for a stop operation.
1316   **SendFrameBuffer** is an API for delivering the buffer of each frame. All buffer interaction operations with the driver are performed through this API.
1317   SetNodeCallBack is a pipeline. This API is used to set the buffer callback function to DeviceManager.
1318   SetMetaDataCallBack is a metadata callback. This API is used to report the metadata obtained from the bottom layer to the upper layer.
1319   BufferCallback is used to upload the filled data buffer of each frame. This API is used to report the buffer to the pipeline.
1320   **SetAbilityMetaDataTag** specifies the types of metadata to be obtained from the bottom layer. The framework can obtain information about one or more types of hardware devices separately. Therefore, you can use this API to obtain the required metadata.
1321
1322  For details about other APIs, see **drivers/peripheral/camera/hal/adapter/platform/v4l2/src/device_manager/**.
1323
1324#### IPP Adaptation
1325
1326The IPP is an algorithm plugin module in the pipeline. It is loaded by the ippnode to perform algorithm processing on stream data. The ippnode supports simultaneous input of multiple channels of data and output of only one channel of data. The algorithm plugin loaded by the ippnode is specified in the following .hcs file:
1327vendor/${product_company}/${product_name}/hdf_config/uhdf/camera/pipeline_core/ipp_algo_config.hcs
1328
1329```
1330  root {
1331     module="sample";
1332     ipp_algo_config {
1333     algo1 {
1334          name = "example";
1335          description = "example algorithm";
1336          path = "libcamera_ipp_algo_example.z.so";
1337          mode = "IPP_ALGO_MODE_NORMAL";
1338     }
1339     }
1340  }
1341
1342```
1343
1344  **name**: algorithm plugin name.
1345  **description**: functions of the algorithm plugin.
1346  **path**: path of the algorithm plugin.
1347  **mode**: running mode of the algorithm plugin.
1348
1349The running modes of the algorithm plugin are provided by IppAlgoMode in **drivers/peripheral/camera/hal/pipeline_core/ipp/include/ipp_algo.h** and can be extended as required.
1350
1351```
1352  enum IppAlgoMode {
1353      IPP_ALGO_MODE_BEGIN,
1354      IPP_ALGO_MODE_NORMAL = IPP_ALGO_MODE_BEGIN,
1355      IPP_ALGO_MODE_BEAUTY,
1356      IPP_ALGO_MODE_HDR,
1357      IPP_ALGO_MODE_END
1358  };
1359```
1360
1361The algorithm plugin is compiled by the GN file **device/${product_company}/${device_name}/camera/BUILD.gn**. The algorithm plugin needs to implement the following APIs (specified by **ipp_algo.h**) for the ippnode to call:
1362
1363      typedef struct IppAlgoFunc {
1364          int (*Init)(IppAlgoMeta* meta);
1365          int (*Start)();
1366          int (*Flush)();
1367          int (*Process)(IppAlgoBuffer* inBuffer[], int inBufferCount, IppAlgoBuffer* outBuffer, IppAlgoMeta* meta);
1368          int (*Stop)();
1369      } IppAlgoFunc;
1370
1371  1) **Init**: initializes the algorithm plugin. It is called by the ippnode before the start operation. **IppAlgoMeta** is defined in **ipp_algo.h** to provide a channel for transferring non-image data between the ippnode and algorithm plugin, such as the current running scenario and face coordinates output after algorithm processing, which can be extended as required.
1372  2) **Start**: called by the ippnode for the start operation.
1373  3) **Flush**: refreshes data. This API is called by the ippnode before the stop operation. When this API is called, the algorithm plugin needs to stop processing as quickly as possible.
1374  4) **Process**: data processing API. Each frame of data is input to the algorithm plugin for processing through this API. **inBuffer** is a group of input buffers, **inBufferCount** is the number of input buffers, **outBuffer** is the output buffer, **meta** is the non-image data generated during algorithm processing, and **IppAlgoBuffer** is defined in **ipp_algo.h**.
1375  5) **Stop**: called by the ippnode for the stop operation.
1376
1377
1378```
1379typedef struct IppAlgoBuffer {
1380      void* addr;
1381      unsigned int width;
1382      unsigned int height;
1383      unsigned int stride;
1384      unsigned int size;
1385      int id;
1386  } IppAlgoBuffer;
1387```
1388
1389In the preceding code, **id** indicates the ID of the port corresponding to the ippnode. For example, if the ID of **inBuffer[0]** is 0, **inBuffer[0]** corresponds to input port 0 of the ippnode. Note that **outBuffer** can be empty. In this case, one input buffer is transferred to the next node by the ippnode as the output buffer. At least one buffer in **inBuffer** is not empty. The input and output buffers are determined by the pipeline configuration.
1390For example, in the common preview scenario where there is no algorithm processing and only one channel of photographing data is transmitted to the ippnode, there is only one input buffer and the output buffer is empty. That is, the input buffer of the algorithm plugin is transparently transmitted.
1391For example, in the scenario where the algorithm plugin combines two channels of preview image data, the first channel of buffer needs to be previewed and sent for display. Copy the image of the second channel to the buffer of the first channel. In this case, there are two input buffers and the output buffer is empty.
1392For example, in the preview data format conversion scenario in the algorithm plugin, YUV data is converted into RGBA data. If there is only one YUV input buffer, the RGBA buffer cannot be output. In this case, a new buffer is required, and the output port buffer of the ippnode is transferred to the algorithm plugin as **outBuffer**. That is, there is only one input buffer and one output buffer.
1393
1394For details about the port configuration of the ippnode, see the description of **config.hcs** in section 3.3.
1395
1396#### V4L2 Driver Adaptation Instance
1397
1398This section describes how to adapt the RK3568 development board in the v4l2 framework.
1399
1400 Distinguish the code related to the V4L2 platform and place it in the **drivers/peripheral/camera/hal/adapter/platform/v4l2** directory, which contains the **device_manager**, **driver_adapter**, and **pipeline_core** directories. The **driver_adapter** directory stores the code related to the v4l2 protocol. They can be used to interact with the v4l2 underlying driver. The **Pipeline_core** directory in this directory and the code in **drivers/peripheral/camera/hal/pipeline_core** form the pipeline framework. **v4l2_source_node** and **uvc_node** are dedicated nodes for v4l2. The **device_manager** directory stores the code for interaction between **device_manager** and **pipeline** and between the south and v4l2 adapter.
1401
1402```
1403  drivers/peripheral/camera/hal/adapter/platform/v4l2/src/
1404  ├── device_manager
1405  │   ├── enumerator_manager.cpp
1406  │   ├── flash_controller.cpp
1407  │   ├── flash_manager.cpp
1408  │   ├── idevice_manager.cpp
1409  │   ├── include
1410  │   ├── isp_controller.cpp
1411  │   ├── isp_manager.cpp
1412  │   ├── sensor_controller.cpp
1413  │   ├── sensor_manager.cpp
1414  │   └── v4l2_device_manager.cpp
1415  ├── driver_adapter
1416  │   ├── BUILD.gn
1417  │   ├── include
1418  │   ├── main_test
1419  │   └── src
1420  └── pipeline_core
1421      └── nodes
1422```
1423
1424 Distinguish the code related to the V4L2 chipset and place it in the **device/ ${product_company}/${device_name} /camera** directory.
1425
1426```
1427  ├── BUILD.gn
1428  ├── camera_demo
1429  │   └── project_camera_demo.h
1430  ├── include
1431  │   └── device_manager
1432  ├── product.gni
1433  └── src
1434      ├── device_manager
1435      ├── driver_adapter
1436      └── pipeline_core
1437```
1438
1439The **driver_adapter** directory contains the header files of the test cases related to the RK3568 driver adapter. The **Camera_demo** directory stores the chipset-related header files of the demo test cases in the camera HAL. **device_manager** stores the code for the camera sensor adapted RK3568 to read device capabilities. In the directory, **project_hardware.h** is critical and stores the list of devices supporting the chipset. The sample code is as follows:
1440
1441```
1442 namespace OHOS::Camera {
1443    std::vector<HardwareConfiguration> hardware = {
1444        {CAMERA_FIRST, DM_M_SENSOR, DM_C_SENSOR, (std::string) "rkisp_v5"},
1445        {CAMERA_FIRST, DM_M_ISP, DM_C_ISP, (std::string) "isp"},
1446        {CAMERA_FIRST, DM_M_FLASH, DM_C_FLASH, (std::string) "flash"},
1447        {CAMERA_SECOND, DM_M_SENSOR, DM_C_SENSOR, (std::string) "Imx600"},
1448        {CAMERA_SECOND, DM_M_ISP, DM_C_ISP, (std::string) "isp"},
1449        {CAMERA_SECOND, DM_M_FLASH, DM_C_FLASH, (std::string) "flash"}
1450   };
1451  } // namespace OHOS::Camera
1452```
1453
1454You can modify compilation options so that the compilation of V4L2 and other framework code can be distinguished based on different compilation chipsets. Add **device/${product_company}/${device_name}/camera/product.gni**.
1455
1456```
1457  camera_product_name_path = "//vendor/${product_company}/${product_name}"
1458  camera_device_name_path = "//device/board/${product_company}/${device_name}"
1459  is_support_v4l2 = true
1460  if (is_support_v4l2) {
1461      is_support_mpi = false
1462      defines += [ "SUPPORT_V4L2" ]
1463      chipset_build_deps = "$camera_device_name_path/camera/:chipset_build"
1464      camera_device_manager_deps =
1465          "$camera_device_name_path/camera/src/device_manager:camera_device_manager"
1466      camera_pipeline_core_deps =
1467          "$camera_device_name_path/camera/src/pipeline_core:camera_pipeline_core"
1468  }
1469```
1470
1471When **product.gni** is loaded by **//drivers/peripheral/camera/hal/camera.gni**, the V4L2 code needs to be compiled. In **//drivers/peripheral/camera/hal/camera.gni**, load the corresponding GNI file based on **product_name** and **device_name** input during compilation.
1472
1473  ```
1474    import("//build/ohos.gni")
1475    if ("${product_name}" == "ohos-arm64") {
1476      import(
1477          "//drivers/peripheral/camera/hal/adapter/chipset/rpi/rpi3/device/camera/product.gni")
1478    } else if ("${product_name}" == "Hi3516DV300") {
1479      import(
1480          "//device/soc/hisilicon/common/hal/media/camera/hi3516dv300/linux_standard/camera/product.gni")
1481  ```
1482
1483 Different chipsets are compiled based on **chipset_build_deps**, **camera_device_manager_deps**, and **camera_pipeline_core_deps** in **drivers/peripheral/camera/hal/BUILD.gn**.
1484
1485         print("product_name : , ${product_name}")
1486          group("camera_hal") {
1487            if (is_standard_system) {
1488              deps = [
1489                "$camera_path/../interfaces/hdi_ipc/client:libcamera_client",
1490                "buffer_manager:camera_buffer_manager",
1491                "device_manager:camera_device_manager",
1492                "hdi_impl:camera_hdi_impl",
1493                "init:ohos_camera_demo",
1494                "pipeline_core:camera_pipeline_core",
1495                "utils:camera_utils",
1496              ]
1497              deps += [ "${chipset_build_deps}" ]
1498            }
1499
1500
1501The camera HAL layer shields the differences between the platform and chip and provides unified APIs for external systems (camera service or test program). The APIs are defined in **drivers/peripheral/camera/interfaces/include**.
1502
1503            ├── icamera_device_callback.h
1504            ├── icamera_device.h
1505            ├── icamera_host_callback.h
1506            ├── icamera_host.h
1507            ├── ioffline_stream_operator.h
1508            ├── istream_operator_callback.h
1509            ├── istream_operator.h
1510
1511During the test, you only need to test the provided external APIs to test the complete code of the camera HAL layer. For details about the APIs, see **README_zh.md** in **drivers/peripheral/camera/interfaces** and header file API definition. For details about the API call process, see the test demo **drivers/peripheral/camera/hal/init**.
1512
1513###  FAQs of Camera Adaptation
1514
1515#### Modifying the SUBWINDOW_TYPE and Display Format
1516
1517Change the RGBA888 display mode from **video** to **normal** (specified by **SUBWINDOW_TYPE**).
1518
1519The OpenHarmony implements the camera of the Hi3516 platform earlier, which uses the PIXEL_FMT_YCRCB_420_SP format for display. However, the RK3568 needs to convert YUV420 preview streams into PIXEL_FMT_RGBA_8888 and send them to the screen for correct display. Modify the following content in the **foundation/ace/ace_engine/frameworks/core/components/camera/standard_system/camera.cpp** file. This file is compiled in **libace.z.so**.
1520
1521
1522      #ifdef PRODUCT_RK
1523          previewSurface_->SetUserData(SURFACE_FORMAT, std::to_string(PIXEL_FMT_RGBA_8888));
1524          previewSurface_->SetUserData(CameraStandard::CameraManager::surfaceFormat,
1525                                       std::to_string(OHOS_CAMERA_FORMAT_RGBA_8888));
1526      #else
1527          previewSurface_->SetUserData(SURFACE_FORMAT, std::to_string(PIXEL_FMT_YCRCB_420_SP));
1528          previewSurface_->SetUserData(CameraStandard::CameraManager::surfaceFormat,
1529                                       std::to_string(OHOS_CAMERA_FORMAT_YCRCB_420_SP));
1530      #endif
1531
1532The following content in the **foundation/multimedia/camera_standard/services/camera_service/src/hstream_repeat.cpp** file is compiled in **libcamera_service.z.so**:
1533
1534```
1535void HStreamRepeat::SetStreamInfo(std::shared_ptr<Camera::StreamInfo> streamInfo)
1536    {
1537        int32_t pixelFormat;
1538        auto it = g_cameraToPixelFormat.find(format_);
1539        if (it != g_cameraToPixelFormat.end()) {
1540            pixelFormat = it->second;
1541        } else {
1542    #ifdef RK_CAMERA
1543            pixelFormat = PIXEL_FMT_RGBA_8888;
1544    #else
1545            pixelFormat = PIXEL_FMT_YCRCB_420_SP;
1546    #endif
1547```
1548
1549In the preceding information, the Hi3516 platform uses the VO module driver to directly send display signals. Therefore, the subwindows mode configured in the ACE is **SUBWINDOW_TYPE_VIDEO**. Modify the **foundation/ace/ace_engine/frameworks/core/components/camera/standard_system/camera.cpp** file. This file is compiled in **libace.z.so**.
1550
1551      #ifdef PRODUCT_RK
1552          option->SetWindowType(SUBWINDOW_TYPE_NORMAL);
1553      #else
1554          option->SetWindowType(SUBWINDOW_TYPE_VIDEO);
1555      #endif
1556
1557#### Adding rk_codec_node
1558
1559RGB conversion and H.264 and JPEG encoding and decoding are performed on this node. Each node in the pipeline model of the camera HAL is in camera data rotation. Currently, the camera HAL V4L2 adapter supports data rotation of only one stream. Therefore, the photographing and recording streams must be copied from a single preview stream. Currently, OpenHarmony does not have a dedicated server for codec and RGB conversion and JPEG compression. In this case, you can only create a dedicated node in the camera HAL, that is, **rk_codec_node**.
1560Add the **rk_codec_node** connection model to HCS.
1561Modify the **vendor/hihope/rk3568/hdf_config/uhdf/camera/pipeline_core/config.hcs** file.
1562
1563
1564              normal_preview_snapshot :: pipeline_spec {
1565                    name = "normal_preview_snapshot";
1566                    v4l2_source :: node_spec {
1567                        name = "v4l2_source#0";
1568                        status = "new";
1569                        out_port_0 :: port_spec {
1570                            name = "out0";
1571                            peer_port_name = "in0";
1572                            peer_port_node_name = "fork#0";
1573                            direction = 1;
1574                        }
1575                    }
1576                    fork :: node_spec {
1577                        name = "fork#0";
1578                        status = "new";
1579                        in_port_0 :: port_spec {
1580                            name = "in0";
1581                            peer_port_name = "out0";
1582                            peer_port_node_name = "v4l2_source#0";
1583                            direction = 0;
1584                        }
1585                        out_port_0 :: port_spec {
1586                            name = "out0";
1587                            peer_port_name = "in0";
1588                            peer_port_node_name = "RKCodec#0";
1589                            direction = 1;
1590                        }
1591                        out_port_1 :: port_spec {
1592                            name = "out1";
1593                            peer_port_name = "in0";
1594                            peer_port_node_name = "RKCodec#1";
1595                            direction = 1;
1596                        }
1597                    }
1598                    RKCodec_1 :: node_spec {
1599                        name = "RKCodec#0";
1600                        status = "new";
1601                        in_port_0 :: port_spec {
1602                            name = "in0";
1603                            peer_port_name = "out0";
1604                            peer_port_node_name = "fork#0";
1605                            direction = 0;
1606                        }
1607                        out_port_0 :: port_spec {
1608                            name = "out0";
1609                            peer_port_name = "in0";
1610                            peer_port_node_name = "sink#0";
1611                            direction = 1;
1612                        }
1613                    }
1614                    RKCodec_2 :: node_spec {
1615                        name = "RKCodec#1";
1616
1617
1618The preview and photographing streams are used as an example. **v4l2_source_node** is the data source and flows to **fork_node**. **rork_node** directly sends the preview data to the RKCodec node and copies the photographing data stream to the RKCodec node for conversion. The converted data is sent to the sink node and then to the consumer of the buffer.
1619
1620Add the compilation of **rk_codec_node.cpp** and related dependent libraries to **device/board/hihope/rk3568/camera/src/pipeline_core/BUILD.gn**. **librga** is the library for converting YUV images into RGB images, **libmpp** is the library for encoding and decoding YUV images into H.264 images, and **libjpeg** is the library for compressing YUV images into JPEG images.
1621
1622
1623        ohos_shared_library("camera_pipeline_core") {
1624            sources = [
1625              "$camera_device_name_path/camera/src/pipeline_core/node/rk_codec_node.cpp",
1626              "$camera_path/adapter/platform/v4l2/src/pipeline_core/nodes/uvc_node/uvc_node.cpp",
1627                      "$camera_path/adapter/platform/v4l2/src/pipeline_core/nodes/v4l2_source_node/v4l2_source_node.cpp",
1628               deps = [
1629                "$camera_path/buffer_manager:camera_buffer_manager",
1630                "$camera_path/device_manager:camera_device_manager",
1631                "//device/soc/rockchip/hardware/mpp:libmpp",
1632                "//device/soc/rockchip/hardware/rga:librga",
1633                "//foundation/multimedia/camera_standard/frameworks/native/metadata:metadata",
1634                "//third_party/libjpeg:libjpeg_static",
1635
1636
1637 Main APIs of the **openharmony/device/board/hihope/rk3568/camera/src/pipeline_core/node/rk_codec_node.cpp** file:
1638
1639
1640       void RKCodecNode::DeliverBuffer(std::shared_ptr\<IBuffer>& buffer)
1641        {
1642            if (buffer == nullptr) {
1643                CAMERA_LOGE("RKCodecNode::DeliverBuffer frameSpec is null");
1644                return;
1645            }
1646
1647            int32_t id = buffer->GetStreamId();
1648            CAMERA_LOGE("RKCodecNode::DeliverBuffer StreamId %{public}d", id);
1649            if (buffer->GetEncodeType() == ENCODE_TYPE_JPEG) {
1650                Yuv420ToJpeg(buffer);
1651            } else if (buffer->GetEncodeType() == ENCODE_TYPE_H264) {
1652                Yuv420ToH264(buffer);
1653            } else {
1654                Yuv420ToRGBA8888(buffer);
1655            }
1656
1657The data stream generated by **fork_node** is delivered to the **DeliverBuffer** API of the rk_codec_node. The API performs conversion based on the value of **EncodeType**. The converted buffers are delivered to the next-level node for processing until they are delivered to the buffer consumer.
1658
1659####  Inconsistent H.264 Frame and Audio Timestamps
1660
1661Issue: When creating a recorder, ACE obtains both audio and video data and combines them into an .mp4 file. However, during the actual synthesis, the timestamps in the audio and video information must be consistent. If they are inconsistent, the Recorder fails. After the recording button is clicked in the camera app, the recording cannot be stopped properly. After the recording is forcibly stopped, the MP4 file is empty.
1662
1663Solution: Find the method of obtaining the audio timestamp of the audio module.
1664
1665```
1666   int32_t AudioCaptureAsImpl::GetSegmentInfo(uint64_t &start)
1667    {
1668        CHECK_AND_RETURN_RET(audioCapturer_ != nullptr, MSERR_INVALID_OPERATION);
1669        AudioStandard::Timestamp timeStamp;
1670        auto timestampBase = AudioStandard::Timestamp::Timestampbase::MONOTONIC;
1671        CHECK_AND_RETURN_RET(audioCapturer_->GetAudioTime(timeStamp, timestampBase), MSERR_UNKNOWN);
1672        CHECK_AND_RETURN_RET(timeStamp.time.tv_nsec >= 0 && timeStamp.time.tv_sec >= 0, MSERR_UNKNOWN);
1673        if (((UINT64_MAX - timeStamp.time.tv_nsec) / SEC_TO_NANOSECOND) <= static_cast<uint64_t>(timeStamp.time.tv_sec)) {
1674            MEDIA_LOGW("audio frame pts too long, this shouldn't happen");
1675        }
1676        start = timeStamp.time.tv_nsec + timeStamp.time.tv_sec * SEC_TO_NANOSECOND;
1677        MEDIA_LOGI("timestamp from audioCapturer: %{public}" PRIu64 "", start);
1678        return MSERR_OK;
1679    }
1680```
1681
1682In the **audio_capture_as_impl.cpp** file, and the camera module uses **CLOCK_REALTIME**, that is, the actual system time.
1683
1684
1685                mppStatus_ = 1;
1686                buf_size = ((MpiEncTestData *)halCtx_)->frame_size;
1687
1688                ret = hal_mpp_encode(halCtx_, dma_fd, (unsigned char *)buffer->GetVirAddress(), &buf_size);
1689                SearchIFps((unsigned char *)buffer->GetVirAddress(), buf_size, buffer);
1690
1691                buffer->SetEsFrameSize(buf_size);
1692                clock_gettime(CLOCK_MONOTONIC, &ts);
1693                timestamp = ts.tv_nsec + ts.tv_sec * TIME_CONVERSION_NS_S;
1694                buffer->SetEsTimestamp(timestamp);
1695                CAMERA_LOGI("RKCodecNode::Yuv420ToH264 video capture on\n");
1696
1697 Solution: Change the time type in **rk_codec_node.cpp** of camera HAL to **CLOCK_MONOTONIC**.
1698
1699####  Linux 4.19 Match Error After the Value of time_t Is Changed to 64-Bit
1700
1701Background: When RK3568 encounters this problem, the upper-layer 32-bit system is running, and the bottom-layer kernel is 64-bit kernel of Linux 4.19. In a 32-bit system environment, the value of **time_t** is of the long type, that is, 32-bit. However, after the value of **time_t** is changed to the 64-bit, an error is reported by camera V4l2 in the IOCTL.
1702
1703      TYPEDEF _Int64 time_t;
1704      TYPEDEF _Int64 suseconds_t;
1705
1706  The specific error and temporary solution are as follows:
1707
1708  1. When an error occurs, search for **camera_host** in Hilog. It is found that a **Not a tty** error is reported when the **VIDIOC_QUERYBUF** CMD is delivered in the **V4L2AllocBuffer** API. The sample code is as follows:
1709
1710```
1711V4L2AllocBuffer error:ioctl VIDIOC_QUERYBUF failed: Not a tty
1712
1713```
1714
1715    RetCode HosV4L2Buffers::V4L2AllocBuffer(int fd, const std::shared_ptr\<FrameSpec>& frameSpec)
1716    {
1717        struct v4l2_buffer buf = {};
1718        struct v4l2_plane planes[1] = {};
1719        CAMERA_LOGD("V4L2AllocBuffer\n");
1720
1721        if (frameSpec == nullptr) {
1722            CAMERA_LOGE("V4L2AllocBuffer frameSpec is NULL\n");
1723            return RC_ERROR;
1724        }
1725
1726        switch (memoryType_) {
1727            case V4L2_MEMORY_MMAP:
1728                // to do something
1729                break;
1730            case V4L2_MEMORY_USERPTR:
1731                buf.type = bufferType_;
1732                buf.memory = memoryType_;
1733                buf.index = (uint32_t)frameSpec->buffer_->GetIndex();
1734
1735                if (bufferType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
1736                    buf.m.planes = planes;
1737                    buf.length = 1;
1738                }
1739                CAMERA_LOGD("V4L2_MEMORY_USERPTR Print the cnt: %{public}d\n", buf.index);
1740
1741                if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
1742                    CAMERA_LOGE("error: ioctl VIDIOC_QUERYBUF failed: %{public}s\n", strerror(errno));
1743                    return RC_ERROR;
1744 2. Generally, the CMD called by the IOCTL system uses **sizeof** of the third parameter as the CMD value and transfers the value to the kernel to search for the corresponding switch case in the kernel. As shown below, **v4l2_buffer** is the main part of the **VIDIOC_QUERYBUF** macro value. If the size of **v4l2_buffer** changes, the value of **VIDIOC_QUERYBUF** also changes accordingly.
1745
1746```
1747  #define VIDIOC_S_FMT        _IOWR('V',  5, struct v4l2_format)
1748  #define VIDIOC_REQBUFS      _IOWR('V',  8, struct v4l2_requestbuffers)
1749  #define VIDIOC_QUERYBUF     _IOWR('V',  9, struct v4l2_buffer)
1750  #define VIDIOC_G_FBUF        _IOR('V', 10, struct v4l2_framebuffer)
1751```
1752
1753  3. When the **CONFIG_COMPAT** macro is enabled in the kernel, the 32-bit system is compatible with the 64-bit kernel. For the IOCTL delivered by the 32-bit system, the API in the following is used to convert the CMD value from 32-bit to 64-bit.
1754
1755      long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
1756      {
1757          struct video_device *vdev = video_devdata(file);
1758          long ret = -ENOIOCTLCMD;
1759
1760          if (!file->f_op->unlocked_ioctl)
1761              return ret;
1762
1763          if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
1764              ret = do_video_ioctl(file, cmd, arg);
1765          else if (vdev->fops->compat_ioctl32)
1766              ret = vdev->fops->compat_ioctl32(file, cmd, arg);
1767
1768 4. In this case, a value of **VIDIOC_QUERYBUF** considered by the kernel is defined in the kernel.
1769
1770        #define VIDIOC_S_FMT32      _IOWR('V',  5, struct v4l2_format32)
1771        #define VIDIOC_QUERYBUF32   _IOWR('V',  9, struct v4l2_buffer32)
1772        #define VIDIOC_QUERYBUF32_TIME32 _IOWR('V',  9, struct v4l2_buffer32_time32)
17735. As mentioned above, the value of **time_t** in the upper-layer MUSL has been changed from 32-bit to 64-bit, and **time_t** is used in struct timeval in the v4l2_buffer structure. In this case, the size of v4l2_buffer at the application layer is different from that at the kernel layer because **kernel_time_t** defined by the kernel in **time.h** is used during compilation in struct timeval of the kernel. As a result, the **sizeof** calculation of v4l2_buffer at the application layer is inconsistent with that at the driver layer, and CMD error cannot be found after the kernel mode is called.
1774
1775```
1776   struct v4l2_buffer {
1777            __u32           index;
1778             __u32           type;
1779            __u32           bytesused;
1780            __u32           flags;
1781            __u32           field;
1782            struct timeval      timestamp;
1783            struct v4l2_timecode    timecode;
1784            __u32           sequence;
1785```
17866. The temporary solution is to change struct timeval in **videodev2.h** to a temporarily defined structure to ensure that the sizes of the upper and lower layers are the same. The sample code is as follows:
1787
1788```
1789            struct timeval1 {
1790                long tv_sec;
1791                long tv_usec;
1792            }
1793            struct v4l2_buffer {
1794                __u32           index;
1795                __u32           type;
1796                __u32           bytesused;
1797                __u32           flags;
1798                __u32           field;
1799                struct timeval1      timestamp;
1800                struct v4l2_timecode    timecode;
1801```
1802
1803 Solution:
1804
1805 There are only two ways to completely solve this problem. 1. Upgrade the system to 64-bit to ensure that the size of the **time_t** variable in user mode is the same as that in kernel mode. 2. Upgrade the kernel to a version later than 5.10.
1806 This problem is solved in the **videodev2.h** file of kernel 5.10. As shown below, the 64-bit **time_t** value is considered during kernel compilation.
1807
1808```
1809struct v4l2_buffer {
1810            __u32           index;
1811            __u32           type;
1812            __u32           bytesused;
1813            __u32           flags;
1814            __u32           field;
1815        #ifdef __KERNEL__
1816            struct __kernel_v4l2_timeval timestamp;
1817        #else
1818            struct timeval      timestamp;
1819        #endif
1820            struct v4l2_timecode    timecode;
1821 }
1822
1823 struct __kernel_v4l2_timeval {
1824      long long   ._sec;
1825  #if defined(__sparc__) && defined(__arch64__)
1826      int     tv_usec;
1827      int     __pad;
1828  #else
1829      long long   tv_usec;
1830  #endif
1831  };
1832```
1833####  H.264 Key Frame Obtaining and Reporting
1834
1835 In addition to the encoded and decoded data, H.264 also needs to report the key frame information. So, how can we know whether a frame is a key frame? The information is required during MP4 encoding. You can determine a key frame as follows: Analyze the NALU header information. NALU type & 0x1f indicate the frame type. The NALU header starts with 0x00000001 or 0x000001.  This figure shows the frame types when **nal_unit_type** is set to different values. Pay attention to the IDR frame information when **nal_unit_type** is set to **5**.
1836         ![1647875911244](figures/dayu200/dayu200-camera-03.png)
1837
1838
1839  IDR frame analysis is coded in the **rk_cedec_node.cpp** file.
1840
1841        static constexpr uint32_t nalBit = 0x1F;
1842        #define NAL_TYPE(value)             ((value) & nalBit)
1843        void RKCodecNode::SearchIFps(unsigned char* buf, size_t bufSize, std::shared_ptr\<IBuffer>& buffer)
1844        {
1845            size_t nalType = 0;
1846            size_t idx = 0;
1847            size_t size = bufSize;
1848            constexpr uint32_t nalTypeValue = 0x05;
1849
1850            if (buffer == nullptr || buf == nullptr) {
1851                CAMERA_LOGI("RKCodecNode::SearchIFps parameter == nullptr");
1852                return;
1853            }
1854
1855            for (int i = 0; i < bufSize; i++) {
1856                int ret = findStartCode(buf + idx, size);
1857                if (ret == -1) {
1858                    idx += 1;
1859                    size -= 1;
1860                } else {
1861                    nalType = NAL_TYPE(buf[idx + ret]);
1862                    CAMERA_LOGI("ForkNode::ForkBuffers nalu == 0x%{public}x buf == 0x%{public}x \n", nalType, buf[idx + ret]);
1863
1864Each buffer converted by H.264 is transferred to the **SearchIFps** API to search for IDR frames. The **findStartCode()** API scans the content in the buffer byte by byte to find the NALU header.
1865
1866  ```
1867     int RKCodecNode::findStartCode(unsigned char *data, size_t dataSz)
1868        {
1869            constexpr uint32_t dataSize = 4;
1870            constexpr uint32_t dataBit2 = 2;
1871            constexpr uint32_t dataBit3 = 3;
1872
1873            if (data == nullptr) {
1874                CAMERA_LOGI("RKCodecNode::findStartCode parameter == nullptr");
1875                return -1;
1876            }
1877
1878            if ((dataSz > dataSize) && (data[0] == 0) && (data[1] == 0) && \
1879                (data[dataBit2] == 0) && (data[dataBit3] == 1)) {
1880                return 4; // 4:start node
1881            }
1882
1883            return -1;
1884        }
1885  ```
1886After the NALU header is found, **nal_unit_type** is found for &0x1F. If the value of **nal_unit_type** is **5**, key frame information is marked and reported through the **buffer->SetEsKeyFrame(1)** API.
1887
1888##     TP
1889
1890### TP Driver Model
1891
1892This model mainly defines and implements the following types of HDIs of the input module, allowing upper-layer input services to perform operations for the input devices:
1893
1894- **Input Manager**: manages input devices, including enabling and disabling input devices and obtaining the device list.
1895- **Input Reporter**: reports input events, including registering and unregistering data reporting callbacks.
1896- **Input Controller**: controls input devices, including obtaining the device information and device type, and setting power supply status.
1897
1898**Figure 1** HDI architecture of the input module
1899
1900![dayu200-tp-01.png](figures/dayu200/dayu200-tp-01.png)
1901
1902The source code directory structure is as follows:
1903
1904```
1905/drivers/peripheral/input
1906├── hal                # HAL code
1907│   └── include       # HAL header files
1908│   └── src           # HAL code implementation
1909├── interfaces         # Driver capability APIs provided for upper-layer services
1910│   └── include       # APIs exposed externally
1911├── test               # Test code
1912│   └── unittest      # Unit test code
1913```
1914
1915For details, see [README](https://gitee.com/openharmony/drivers_peripheral/blob/master/input/README_zh.md) of the input subsystem.
1916
1917### TP HDF Driver Adaptation
1918
1919#### Files and Directories Involved in the TP Driver
1920
1921By default, the DAYU 200 platform supports the GT5688 TP IC.
1922
1923Files and directories involved in porting the touch driver on the development board:
1924
19251. Makefile: drivers\adapter\khdf\linux\model\input\Makefile
1926
19272. vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs
1928
19293. vendor\hihope\rk3568\hdf_config\khdf\input\input_config.hcs
1930
19314. drivers\framework\model\input\driver\touchscreen
1932
1933The adaptation of the TP driver involves the TP driver and HCS configuration.
1934
1935The adaptation of the TP driver depends on the HDF input model. The HDF input model supports device registration, management, data forwarding layer, and HCS parsing in TP, key, and HID scenarios. The input model of the HDF can be abstracted into three layers: driver management layer, common driver layer, and component driver layer.
1936
1937The following figure shows the framework of the HDF input module from the perspective of functions.
1938
1939![dayu200-tp-02.png](figures/dayu200/dayu200-tp-02.png)
1940
1941Due to the high abstraction and integration of the HDF input model, the adapted driver of the TP driver mainly involves the adaptation of the component driver layer.
1942
1943Before adaptation, you need to determine the resources required by the TP.
1944
1945For hardware resources, the TP module requires the following resources on the host:
1946
19471. Interrupt pin
1948
19492. Reset pin
1950
19513. Used I2C group and address of the slave device
1952
19534. TP initialization firmware (usually provided by IC vendors)
1954
19555. Touchscreen resolution
1956
1957For software resources, TP adaptation on the HDF depends on the following HDF basic modules:
1958
19591. HDF GPIO subsystem: sets GPIO pins and interrupt resources.
1960
19612. HDF I2C subsystem: used for I2C communication.
1962
19633. Input model
1964
1965The component driver is used based on the following structures:
1966
1967```
1968static struct TouchChipOps g_gt911ChipOps = {
1969    .Init = ChipInit,
1970    .Detect = ChipDetect,
1971    .Resume = ChipResume,
1972    .Suspend = ChipSuspend,
1973    .DataHandle = ChipDataHandle,
1974    .UpdateFirmware = UpdateFirmware,
1975    .SetAbility = SetAbility,
1976};
1977```
1978
1979**ChipInit** initializes the component driver.
1980
1981**ChipDetect** checks the component validity after initialization.
1982
1983**SetAbility** sets key attributes.
1984
1985**ChipDataHandle** parses key values.
1986
1987**UpdateFirmware** upgrades firmware.
1988
1989**ChipSuspend** suspends components.
1990
1991**ChipResume** resumes components.
1992
1993Implement the preceding API callbacks based on the component features and register the structure with the input model.
1994
1995#### HCS Configuration
1996
1997Add a new component node to **device_info.hcs**.
1998
1999```
2000device_touch_chip :: device {
2001                device0 :: deviceNode {
2002                    policy = 0;
2003                    priority = 180;
2004                    preload = 0; // The driver is loaded by default.
2005                    permission = 0660;
2006                    moduleName = "HDF_TOUCH_GT911";// The value must be the same as that in the component driver.
2007                    serviceName = "hdf_touch_gt911_service";
2008                    deviceMatchAttr = "zsj_gt911_5p5";
2009                }
2010            }
2011```
2012
2013Add component features to **input_config.hcs**.
2014
2015```
2016chipConfig {
2017                    template touchChip {
2018                        match_attr = "";
2019                        chipName = "gt911";
2020                        vendorName = "zsj";
2021                        chipInfo = "AAAA11222";  // 4-ProjectName, 2-TP IC, 3-TP Module
2022                        /* 0:i2c 1:spi*/
2023                        busType = 0;
2024                        deviceAddr = 0x5D;
2025                        /* 0:None 1:Rising 2:Failing 4:High-level 8:Low-level */
2026                        irqFlag = 2;
2027                        maxSpeed = 400;
2028                        chipVersion = 0; //parse Coord TypeA
2029                        powerSequence {
2030                            /* [type, status, dir , delay]
2031                                <type> 0:none 1:vcc-1.8v 2:vci-3.3v 3:reset 4:int
2032                                <status> 0:off or low  1:on or high  2:no ops
2033                                <dir> 0:input  1:output  2:no ops
2034                                <delay> meanings delay xms, 20: delay 20ms
2035                             */
2036                            powerOnSeq = [4, 0, 1, 5,
2037                                         3, 0, 1, 10,
2038                                         3, 1, 1, 60,
2039                                         4, 2, 0, 50];
2040                            suspendSeq = [3, 0, 2, 10];
2041                            resumeSeq = [3, 1, 2, 10];
2042                            powerOffSeq = [3, 0, 2, 10,
2043                                           1, 0, 2, 20];
2044                        }
2045                    }
2046```
2047
2048## Display Adaptation
2049
2050The following tasks need to be performed for display adaptation: graphics service HDI API adaptation, GPU adaptation, and LCD driver adaptation.
2051
2052### Display HDI
2053
2054[Display HDI](https://gitee.com/openharmony/drivers_peripheral/blob/master/display/README_zh.md) provides display driver capabilities for graphics services, including display layer management, display memory management, and hardware acceleration. Display HDI adaptation involves **gralloc** and **display_device**.
2055
2056#### Gralloc Adaptation
2057
2058The gralloc module provides the display memory management function. OpenHarmony provides the reference implementation of Hi3516D V300. Vendors can refer to and adapt the implementation based on the actual situation. The implementation is developed based on the DRM. [Source code link](https://gitee.com/openharmony/drivers_peripheral/tree/master/display/hal/default_standard)
2059
2060The DRM device node is defined in the **//drivers_peripheral/display/hal/default_standard/srd/display_gralloc/display_gralloc_gbm.c** file. You can modify the file as required.
2061
2062```
2063const char *g_drmFileNode = "/dev/dri/card0";
2064```
2065
2066In this implementation, a HiSilicon private IOCTL command code **DRM_IOCTL_HISILICON_GEM_FD_TO_PHYADDR** is defined in the **//drivers_peripheral/display/hal/default_standard/src/display_gralloc/hisilicon_drm.h** file and called in the **//drivers_peripheral/display/hal/default_standard/src/display_gralloc/display_gralloc_gbm.c** file. This function is a HiSilicon private function and can be modified as required during adaptation.
2067
2068```
2069...
2070    InitBufferHandle(bo, fd, info, priBuffer);
2071    priBuffer->hdl.phyAddr = GetPhysicalAddr(grallocManager->drmFd, fd);
2072    *buffer = &priBuffer->hdl;
2073...
2074```
2075
2076####  Display Device Adaptation
2077
2078The display device module provides functions such as display device management, layer management, and hardware acceleration.
2079
2080OpenHarmony provides the [DRM-based Hi3516D V300 reference implementation](https://gitee.com/openharmony/drivers_peripheral/tree/master/display/hal/default_standard/src/display_device), which supports hardware composition by default.
2081
2082If the development board does not support hardware composition, skip the initialization of the GFX in the **drm_display.cpp** file.
2083
2084```
2085drivers_peripheral/blob/master/display/hal/default_standard/src/display_device/drm/drm_display.cpp
2086int32_t DrmDisplay::Init()
2087{
2088    ...
2089    ...
2090    ret = HdiDisplay::Init();
2091    DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("init failed"));
2092    auto preComp = std::make_unique<HdiGfxComposition>();
2093    DISPLAY_CHK_RETURN((preComp == nullptr), DISPLAY_FAILURE,
2094        DISPLAY_LOGE("can not new HdiGfxComposition errno %{public}d", errno));
2095    ret = preComp->Init();                                                                                          // GFX initialization, which needs to be skipped.
2096    DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("can not init HdiGfxComposition"));  // Or do not check the return value.
2097
2098    ...
2099}
2100```
2101
2102In addition, modify the **set_layers** method in the **//drivers_peripheral/display/hal/default_standard/src/display_device/hdi_gfx_composition.cpp** file to use the CPU composition display.
2103
2104```
2105int32_t HdiGfxComposition::SetLayers(std::vector<HdiLayer *> &layers, HdiLayer &clientLayer)
2106{
2107    DISPLAY_LOGD("layers size %{public}zd", layers.size());
2108    mClientLayer = &clientLayer;
2109    mCompLayers.clear();
2110    for (auto &layer : layers) {
2111        if (CanHandle(*layer)) {
2112#if 0                                      // CPU composition.
2113            layer->SetDeviceSelect(COMPOSITION_CLIENT);
2114#else
2115            if ((layer->GetCompositionType() != COMPOSITION_VIDEO) &&
2116                (layer->GetCompositionType() != COMPOSITION_CURSOR)) {
2117                layer->SetDeviceSelect(COMPOSITION_DEVICE);
2118            } else {
2119                layer->SetDeviceSelect(layer->GetCompositionType());
2120            }
2121#endif
2122            mCompLayers.push_back(layer);
2123        }
2124    }
2125    DISPLAY_LOGD("composer layers size %{public}zd", mCompLayers.size());
2126    return DISPLAY_SUCCESS;
2127}
2128```
2129
2130#### Test and Verification
2131
2132hello_composer test module: It is a test program provided by the Rosen graphics framework and checks whether the functions such as the display process and HDI API are normal. By default, the module is compiled with the system.
2133
2134Code path:
2135
2136```
2137foundation/graphic/graphic/rosen/samples/composer/
2138├── BUILD.gn
2139├── hello_composer.cpp
2140├── hello_composer.h
2141├── layer_context.cpp
2142├── layer_context.h
2143└── main.cpp
2144```
2145
2146The verification is as follows:
2147
21481. Disable the render service.
2149
2150  ```
2151  service_control stop render_service
2152  ```
2153
21542. Disable the foundation process.
2155
2156  ```
2157  service_control stop foundation
2158  ```
2159
21603. Run **hello_composer** to test related APIs.
2161
2162   ```
2163   ./hello_composer
2164   ```
2165
2166Test using devicetest: test module provided by the HDI display module. It is used to test the HDI API, display buffer, and driver capabilities. During the test, the render service and foundation processes also need to be stopped.
2167
2168Code path: **/drivers/peripheral/display/test/unittest/standard**
2169
2170```
2171├── BUILD.gn
2172├── common
2173│   ├── display_test.h
2174│   ├── display_test_utils.cpp
2175│   └── display_test_utils.h
2176├── display_device
2177│   ├── hdi_composition_check.cpp
2178│   ├── hdi_composition_check.h
2179│   ├── hdi_device_test.cpp
2180│   ├── hdi_device_test.h
2181│   ├── hdi_test_device_common.h
2182│   ├── hdi_test_device.cpp
2183│   ├── hdi_test_device.h
2184│   ├── hdi_test_display.cpp
2185│   ├── hdi_test_display.h
2186│   ├── hdi_test_layer.cpp
2187│   ├── hdi_test_layer.h
2188│   ├── hdi_test_render_utils.cpp
2189│   └── hdi_test_render_utils.h
2190└── display_gralloc
2191    ├── display_gralloc_test.cpp
2192    └── display_gralloc_test.h
2193```
2194
2195### GPU
2196
2197Compiler Clang
2198
2199```
2200prebuilts/clang/ohos/linux-x86_64/llvm
2201```
2202
2203musl Library
2204
2205```
2206./build.sh --product-name rk3568 --build-target musl_all
2207```
2208
2209After the compilation is complete, the following header files and libraries are generated in the **out/{product_name}/obj/third_party/musl/usr/lib** directory:
2210
2211```
221232-bit: arm-linux-ohos
2213
221464-bit: aarch64-linux-ohos
2215```
2216
2217Source code directory:
2218
2219```
2220third_party/musl
2221```
2222
2223GPU compilation parameter reference:
2224
2225```
2226TARGET_CFLAGS=" -march=armv7-a -mfloat-abi=softfp -mtune=generic-armv7-a -mfpu=neon -mthumb --target=arm-linux-ohosmusl -fPIC -ftls-model=global-dynamic -mtls-direct-seg-refs -DUSE_MUSL"
2227```
2228
2229## LCD
2230
2231By default, the DAYU 200 platform supports an LCD screen with the MIPI API.
2232
2233LCD adaptation mainly depends on the HDF display model. The display driver model is developed based on the HDF driver framework, platform API, and OSAL API. It can shield the differences between different kernel forms (LiteOS and Linux), apply to different chip platforms, and provide a unified driver platform for display components.
2234
2235The following figure shows the hierarchy of the HDF display driver model.
2236
2237![640](figures/dayu200/dayu200-lcd-01.png)
2238
2239The current driver model is mainly deployed in kernel mode and connects to the display common HAL layer to assist HDI implementation. The display driver exposes the display driver capability to the graphics service through the display-HDI layer. The display driver connects to the display panel component downwards to drive the screen to work properly and streamlines the entire display process.
2240
2241Therefore, the LCD adaptation mainly lies in the adaptation of the LCD panel component driver.
2242
2243The adaptation of the component driver consists of two parts: panel driver and HCS configuration.
2244
2245The following files are involved:
2246
2247```
2248drivers/framework/model/display/driver/panel
2249
2250vendor/hihope/rk3568/hdf_config/khdf/device_info
2251
2252vendor/hihope/rk3568/hdf_config/khdf/input
2253```
2254
2255### Panel Driver
2256
2257The component driver is used based on the following APIs:
2258
2259```
2260struct PanelData {
2261    struct HdfDeviceObject *object;
2262    int32_t (*init)(struct PanelData *panel);
2263    int32_t (*on)(struct PanelData *panel);
2264    int32_t (*off)(struct PanelData *panel);
2265    int32_t (*prepare)(struct PanelData *panel);
2266    int32_t (*unprepare)(struct PanelData *panel);
2267    struct PanelInfo *info;
2268    enum PowerStatus powerStatus;
2269    struct PanelEsd *esd;
2270    struct BacklightDev *blDev;
2271    void *priv;
2272};
2273```
2274
2275Instantiate the data structure in the initialization API of the driver.
2276
2277    panelSimpleDev->panel.init = PanelSimpleInit;
2278    panelSimpleDev->panel.on = PanelSimpleOn;
2279    panelSimpleDev->panel.off = PanelSimpleOff;
2280    panelSimpleDev->panel.prepare = PanelSimplePrepare;
2281    panelSimpleDev->panel.unprepare = PanelSimpleUnprepare;
2282PanelSimpleInit initializes panel software.
2283
2284PanelSimpleOn turns on the screen.
2285
2286PanelSimpleOff turns off the screen.
2287
2288PanelSimplePrepare initializes the hardware time sequence for turning on the screen.
2289
2290PanelSimpleUnprepare initializes the hardware time sequence for turning off the screen.
2291
2292After instantiation, use the **RegisterPanel** API to register the panel driver with the display model.
2293
2294Note that the LCD on DAYU 200 uses the DRM display framework.
2295
2296### HCS Configuration
2297
2298```
2299device4 :: deviceNode {
2300                    policy = 0;
2301                    priority = 100;
2302                    preload = 0;
2303                    moduleName = "LCD_PANEL_SIMPLE";
2304                }
2305```
2306
2307## Backlight
2308
2309The backlight driver model is developed based on the HDF framework.
2310
2311![dayu200-backlight-01.png](figures/dayu200/dayu200-backlight-01.png)
2312
2313The RK3568 backlight is implemented by controlling the duty cycle by using PWM4.
2314
2315Code path of the native backlight driver:
2316
2317```c
2318linux-5.10/drivers/video/backlight/pwm_bl.c
2319linux-5.10/drivers/video/backlight/backlight.c
2320linux-5.10/drivers/pwm/pwm-rockchip.c
2321```
2322
2323To use the backlight driver on the HDF framework, disable the native driver.
2324
2325```c
2326# CONFIG_BACKLIGHT_PWM is not set
2327```
2328
2329### HDF Implementation
2330
2331Code Path
2332
2333```c
2334drivers/framework/model/display/driver/backlight/hdf_bl.c
2335```
2336
2337HDF BL Entry Function
2338
2339```c
2340static int32_t BacklightInit(struct HdfDeviceObject *object)
2341{
2342    if (object == NULL) {
2343        HDF_LOGE("%s: object is null!", __func__);
2344        return HDF_FAILURE;
2345    }
2346    HDF_LOGI("%s success", __func__);
2347    return HDF_SUCCESS;
2348}
2349
2350struct HdfDriverEntry g_blDevEntry = {
2351    .moduleVersion = 1,
2352    .moduleName = "HDF_BL",
2353    .Init = BacklightInit,
2354    .Bind = BacklightBind,
2355};
2356
2357HDF_INIT(g_blDevEntry);
2358```
2359
2360Code path:
2361
2362```c
2363drivers/framework/model/display/driver/backlight/pwm_bl.c
2364```
2365
2366HDF PWM Entry Function
2367
2368```c
2369struct HdfDriverEntry g_pwmBlDevEntry = {
2370    .moduleVersion = 1,
2371    .moduleName = "PWM_BL",
2372    .Init = BlPwmEntryInit,
2373};
2374
2375HDF_INIT(g_pwmBlDevEntry);
2376```
2377
2378The backlight control APIs are as follows:
2379
2380```c
2381static int32_t BlPwmUpdateBrightness(struct BacklightDev *blDev, uint32_t brightness)
2382{
2383    int32_t ret;
2384    uint32_t duty;
2385    struct BlPwmDev *blPwmDev = NULL;
2386
2387    blPwmDev = ToBlDevPriv(blDev);
2388    if (blPwmDev == NULL) {
2389        HDF_LOGE("%s blPwmDev is null", __func__);
2390        return HDF_FAILURE;
2391    }
2392    if (blPwmDev->props.maxBrightness == 0) {
2393        HDF_LOGE("%s maxBrightness is 0", __func__);
2394        return HDF_FAILURE;
2395    }
2396    if (brightness == 0) {
2397        return PwmDisable(blPwmDev->pwmHandle);
2398    }
2399    duty = (brightness * blPwmDev->config.period) / blPwmDev->props.maxBrightness;
2400    ret = PwmSetDuty(blPwmDev->pwmHandle, duty);
2401    if (ret != HDF_SUCCESS) {
2402        HDF_LOGE("%s: PwmSetDuty failed, ret %d", __func__, ret);
2403        return HDF_FAILURE;
2404    }
2405    return PwmEnable(blPwmDev->pwmHandle);
2406}
2407
2408static struct BacklightOps g_blDevOps = {
2409    .updateBrightness = BlPwmUpdateBrightness,
2410};
2411```
2412
2413Actually, the API implemented by the HDF PWM is used to connect to the kernel PWM.
2414
2415![dayu200-backlight-02.png](figures/dayu200/dayu200-backlight-02.png)
2416
2417Register the backlight with the LCD HDF driver.
2418
2419Code Path
2420
2421```c
2422drivers/framework/model/display/driver/panel/ili9881c_boe.c
2423```
2424
2425```c
2426ili9881cBoeDev->panel.blDev = GetBacklightDev("hdf_pwm");
2427if (ili9881cBoeDev->panel.blDev == NULL) {
2428    HDF_LOGE("%s GetBacklightDev fail", __func__);
2429    goto FAIL;
2430}
2431```
2432
2433### HCS Configuration
2434
2435HCS configuration of the driver
2436
2437```c
2438device_pwm_bl :: device {
2439    device0 :: deviceNode {
2440        policy = 0;
2441        priority = 95;
2442        preload = 0;
2443        moduleName = "PWM_BL";
2444        deviceMatchAttr = "pwm_bl_dev";
2445    }
2446}
2447device_backlight :: device {
2448    device0 :: deviceNode {
2449        policy = 2;
2450        priority = 90;
2451        preload = 0;
2452        permission = 0660;
2453        moduleName = "HDF_BL";
2454        serviceName = "hdf_bl";
2455    }
2456}
2457```
2458
2459HCS configuration for PWM backlight
2460
2461```c
2462root {
2463    backlightConfig {
2464        pwmBacklightConfig {
2465            match_attr = "pwm_bl_dev";
2466            pwmDevNum = 1;
2467            pwmMaxPeriod = 25000;
2468            backlightDevName = "hdf_pwm";
2469            minBrightness = 0;
2470            defBrightness = 127;
2471            maxBrightness = 255;
2472        }
2473    }
2474}
2475```
2476
2477### Testing
2478
2479Run **cat /sys/kernel/debug/pwm** to check whether the HDF PWM has applied for PWM4.
2480
2481If the application is successful, the following information is displayed:
2482
2483**requested**: The application is successful.
2484
2485**enabled**: PWM4 is enabled successfully.
2486
2487```c
2488# cat /sys/kernel/debug/pwm
2489
2490platform/fe6e0000.pwm, 1 PWM device
2491 pwm-0   ((null)              ): requested enabled period: 25000 ns duty: 9705 ns polarity: normal
2492```
2493
2494## **Wi-Fi**
2495
2496### HDF-based Wi-Fi Approach
2497
2498Get familiar with the HDF Wi-Fi framework and main APIs to be implemented by referring to [OpenHarmony HDF Wi-Fi Driver Analysis](https://mp.weixin.qq.com/s/iiE97pqPtzWIZadcjrQtsw), including the implementation of the HDF driver initialization API, Wi-Fi control-side API set, AP mode API set, STA mode API set, network-side API set, and event reporting API.
2499
2500Next, let's get familiar with the HCS file format and the code startup initialization process of the HDF Wi-Fi core driver framework. For details, see the Hi3881 code.
2501
2502HDF Wi-Fi framework
2503
2504​                       ![image-20220320160720306](figures/dayu200/dayu200-wifi-01.png)
2505
2506### Code Process Analysis of the AP6275s Driver
2507
2508####  Analysis of the Driver Module Initialization Process
2509
2510![dayu200-wifi-02.png](figures/dayu200/dayu200-wifi-02.png)
2511
2512The AP6275s is a Wi-Fi module driver of the SDIO device. It uses the standard Linux SDIO device driver. The kernel module initialization entry **module_init()** calls the **dhd_wifi_platform_load_sdio()** function for initialization. Here, **wifi_platform_set_power()** is called to power on the GPIO, **dhd_wlan_set_carddetect()** is called to detect the SDIO card, and **sdio_register_driver(&bcmsdh_sdmmc_driver)** is called to register the SDIO device driver. The SDIO bus has detected that the Wi-Fi module matches the device driver based on the device ID and vendor ID. Therefore, the **bcmsdh_sdmmc_probe()** function of the driver is called back immediately to initialize the Wi-Fi module chip. Finally, create the net_device network API wlan0 and register it with the Linux kernel protocol stack.
2513
2514l Create the wlan0 object of the net_device network API.
2515
2516**dhd_allocate_if()** calls **alloc_etherdev()** to create a **net_device** object, that is, the wlan0 network API.
2517
2518l Register wlan0 with the kernel protocol stack.
2519
2520Call the **dhd_register_if()** function. Here, call **register_netdev(net)** to register the wlan0 network API with the protocol stack.
2521
2522### HDF Wi-Fi Framework Adaptation Through Code Modification
2523
2524To use the Wi-Fi function of the system, the AP mode, STA mode, and P2P mode need to be implemented. The **wpa_supplicant** application interacts with the Wi-Fi driver through the HDF Wi-Fi framework to implement the STA mode and P2P mode, and the **hostapd** application interacts with the Wi-Fi driver through the HDF Wi-Fi framework to implement the AP mode and P2P mode.
2525
2526The AP6275s Wi-Fi 6 kernel driver depends on the platform capability, including the SDIO bus communication capability. The communication with the user mode depends on the HDF Wi-Fi framework capability. After ensuring that the preceding capabilities are normal, you can start the HDF adaptation and porting of the Wi-Fi driver. This part uses the open-source RK3568 code as the basic version for porting.
2527
2528The files and directories involved in the adaptation and porting of the AP6275s Wi-Fi 6 driver are as follows:
2529
25301). Compile configuration files.
2531
2532drivers/adapter/khdf/linux/model/network/wifi/Kconfig
2533
2534drivers/adapter/khdf/linux/model/network/wifi/vendor/Makefile
2535
25362). Access the Wi-Fi driver source code directory.
2537
2538The native driver code is stored in:
2539
2540linux-5.10/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd_wifi6/
2541
2542The code files added and modified on the native driver are stored in the following directory:
2543
2544device/hihope/rk3568/wifi/bcmdhd_wifi6/
2545
2546Directory structure:
2547
2548```
2549./device/hihope/rk3568/wifi/bcmdhd_wifi6/hdf
2550├── hdf_bdh_mac80211.c
2551├── hdf_driver_bdh_register.c
2552├── hdfinit_bdh.c
2553├── hdf_mac80211_ap.c
2554├── hdf_mac80211_sta.c
2555├── hdf_mac80211_sta.h
2556├── hdf_mac80211_sta_event.c
2557├── hdf_mac80211_sta_event.h
2558├── hdf_mac80211_p2p.c
2559├── hdf_public_ap6275s.h
2560├── net_bdh_adpater.c
2561├── net_bdh_adpater.h
2562```
2563
2564**hdf_bdh_mac80211.c** is used to fill in the functions required by **g_bdh6_baseOps**, **hdf_mac80211_ap.c** is used to fill in the functions required by **g_bdh6_staOps**, **hdf_mac80211_sta.c** is used to fill in the functions required by **g_bdh6_staOps**, and **hdf_mac80211_p2p.c** is used to fill in the functions required by **g_bdh6_p2pOps**. For details about the APIs required for basic Wi-Fi functions, see **openharmony/drivers/framework/include/wifi/wifi_mac80211_ops.h**.
2565
2566####  Driver File Compilation
2567
2568The HDF WLAN driver framework consists of seven parts: Module, NetDevice, NetBuf, BUS, HAL, Client, and Message. You can implement the following functions during HDF adaptation of the Wi-Fi driver:
2569
25701. Initialize the driver module that adapts the HDF WLAN framework.
2571
2572   The following figure shows the code process.
2573
2574   ![dayu200-wifi-03.png](figures/dayu200/dayu200-wifi-03.png)
2575
2576   The code is stored in **device/hihope/rk3568/wifi/bcmdhd_wifi6/hdf_driver_bdh_register.c**.
2577
2578   ```
2579   struct HdfDriverEntry g_hdfBdh6ChipEntry = {
2580     .moduleVersion = 1,
2581     .Bind = HdfWlanBDH6DriverBind,
2582     .Init = HdfWlanBDH6ChipDriverInit,
2583     .Release = HdfWlanBDH6ChipRelease,
2584     .moduleName = "HDF_WLAN_CHIPS"
2585   };
2586   HDF_INIT(g_hdfBdh6ChipEntry);
2587   ```
2588
2589   During driver initialization, the SDIO main control board scans and detects the card, initializes the Wi-Fi chip, and creates and initializes the main API.
2590
25912. Implement the HDF WLAN Base control-side APIs.
2592
2593   The code is stored in **hdf_bdh_mac80211.c**.
2594
2595   ```
2596      static struct HdfMac80211BaseOps g_bdh6_baseOps = {
2597     .SetMode = BDH6WalSetMode,
2598     .AddKey = BDH6WalAddKey,
2599     .DelKey = BDH6WalDelKey,
2600     .SetDefaultKey = BDH6WalSetDefaultKey,
2601     .GetDeviceMacAddr = BDH6WalGetDeviceMacAddr,
2602     .SetMacAddr = BDH6WalSetMacAddr,
2603     .SetTxPower = BDH6WalSetTxPower,
2604     .GetValidFreqsWithBand = BDH6WalGetValidFreqsWithBand,
2605     .GetHwCapability = BDH6WalGetHwCapability,
2606     .SendAction = BDH6WalSendAction,
2607     .GetIftype = BDH6WalGetIftype,
2608   };
2609   ```
2610
2611   The preceding APIs are called in STA, AP, and P2P modes.
2612
26133. Implement APIs in HDF WLAN STA mode.
2614
2615   The following figure shows the call process in STA mode.
2616   ![image-20220320161412663](figures/dayu200/dayu200-wifi-04.png)
2617
2618   The code is stored in **hdf_mac80211_sta.c**.
2619
2620   ```
2621   struct HdfMac80211STAOps g_bdh6_staOps = {
2622     .Connect = HdfConnect,
2623     .Disconnect = HdfDisconnect,
2624     .StartScan = HdfStartScan,
2625     .AbortScan = HdfAbortScan,
2626     .SetScanningMacAddress = HdfSetScanningMacAddress,
2627   };
2628   ```
2629
26304. Implement APIs in HDF WLAN AP mode.
2631
2632   The following figure shows the call process in AP mode.
2633
2634 ![image-20220320161432068](figures/dayu200/dayu200-wifi-05.png)
2635
2636The code is stored in **hdf_mac80211_ap.c**.
2637
2638```
2639struct HdfMac80211APOps g_bdh6_apOps = {
2640  .ConfigAp = WalConfigAp,
2641  .StartAp = WalStartAp,
2642  .StopAp = WalStopAp,
2643  .ConfigBeacon = WalChangeBeacon,
2644  .DelStation = WalDelStation,
2645  .SetCountryCode = WalSetCountryCode,
2646  .GetAssociatedStasCount = WalGetAssociatedStasCount,
2647  .GetAssociatedStasInfo = WalGetAssociatedStasInfo
2648};
2649```
2650
26515. Implement APIs in HDF WLAN P2P mode.
2652
2653   The following figure shows the call process in P2P mode.
2654
2655   ![image-20220320161442845](figures/dayu200/dayu200-wifi-06.png)
2656
2657   ```
2658   struct HdfMac80211P2POps g_bdh6_p2pOps = {
2659     .RemainOnChannel = WalRemainOnChannel,
2660     .CancelRemainOnChannel = WalCancelRemainOnChannel,
2661     .ProbeReqReport = WalProbeReqReport,
2662     .AddIf = WalAddIf,
2663     .RemoveIf = WalRemoveIf,
2664     .SetApWpsP2pIe = WalSetApWpsP2pIe,
2665     .GetDriverFlag = WalGetDriverFlag,
2666   };
2667   ```
2668
26696. Implement the event reporting APIs of the HDF WLAN framework.
2670
2671   The Wi-Fi driver needs to report events to the **wpa_supplicant** and **hostapd** applications, such as hotspot scanning results and association completion events of new STAs. For details about all APIs for reporting HDF WLAN events, see **drivers/framework/include/wifi/hdf_wifi_event.h**.
2672
2673   The HDF WLAN APIs for reporting events are as follows.
2674
2675| API in Header File hdf_wifi_event.h   | Description                |
2676| ----------------------------------- | ------------------------ |
2677| HdfWifiEventNewSta()                | Reports a new STA event.     |
2678| HdfWifiEventDelSta ()             | Reports an STA deletion event.     |
2679| HdfWifiEventInformBssFrame ()     | Reports a BSS scanning event.         |
2680| HdfWifiEventScanDone ()           | Reports a scanning completion event.        |
2681| HdfWifiEventConnectResult ()      | Reports a connection result event.        |
2682| HdfWifiEventDisconnected ()       | Reports a disconnection event.        |
2683| HdfWifiEventMgmtTxStatus ()       | Reports sending status events.        |
2684| HdfWifiEventRxMgmt ()             | Reports a receiving status event.        |
2685| HdfWifiEventCsaChannelSwitch ()   | Reports a CSA frequency band switching event.     |
2686| HdfWifiEventTimeoutDisconnected ()| Reports a connection timeout event.        |
2687| HdfWifiEventEapolRecv ()          | Reports an EAPOL receive event.       |
2688| HdfWifiEventResetResult ()        | Reports a WLAN driver reset result event.|
2689| HdfWifiEventRemainOnChannel ()    | Reports a channel holding event.        |
2690| HdfWifiEventCancelRemainOnChannel   | Reports a channel unholding event.    |
2691
2692### Summary of All Key Issues
2693
2694#### Method of Enabling the AP Mode During AP Module Debugging
2695
2696Use the BusyBox and hostapd to configure the AP function as follows:
2697
2698```
2699ifconfig wlan0 up
2700ifconfig wlan0 192.168.12.1 netmask 255.255.255.0
2701busybox udhcpd /data/udhcpd.conf
2702./hostapd -d /data/hostapd.conf
2703```
2704
2705#### Method of Enabling the ATA Mode During STA Module Debugging
2706
2707```
2708wpa_supplicant -iwlan0 -c /data/l2tool/wpa_supplicant.conf -d &
2709./busybox udhcpc -i wlan0 -s /data/l2tool/dhcpc.sh
2710```
2711
2712#### Solution to the Failure to Report the Hotspot Scanning Event to wap_supplicant
2713
2714When the **wpa_supplicant** application is started, the **-B** parameter cannot be added to start the application in the background. If the **-B** parameter is added to start the application in the background, the thread that calls **poll()** to wait for receiving events exits. As a result, the reported events cannot be received.
2715
2716In this case, use **wpa_supplicant -iwlan0 -c /data/wpa_supplicant.conf &** to start the application in the background.
2717
2718#### WPA2PSK Authentication Failure and Timeout
2719
2720According to the process analysis, the hostapd process does not receive the **WIFI_WPA_EVENT_EAPOL_RECV = 13** event. Originally, the driver does not send the received EAPOL packet to the hostapd process through the HDF Wi-Fi framework. After the driver receives the packet, the EAPOL packet is sent to the HDF Wi-Fi framework before **netif_rx()** is called to trigger a software interrupt. The authentication is successful.
2721
2722#### Location and Analysis of Connection Failure in P2P Mode
2723
2724During the debugging of the P2P connection API, it is found that the P2P direct connection page of the mobile phone shows the invited state and the connection fails. By capturing and comparing the packets indicating that the connection between the mobile phone and the Wi-Fi module is successful and the packets indicating that the connection fails after HDF adaptation, you can find that the mobile phone responds with an extra ACTION packet, indicating that the parameter is invalid. Then, the P2P connection is terminated.
2725
2726 ![image-20220320161303057](figures/dayu200/dayu200-wifi-07.png)
2727
2728Check the content of the ACTION packet sent by the Wi-Fi module to the mobile phone. It is found that the MAC address in P2P Device Info is incorrect, as shown below.
2729
2730Correct frame content
2731
2732 ![image-20220320161314006](figures/dayu200/dayu200-wifi-08.png)
2733
2734Incorrect frame content
2735
2736 ![image-20220320161318995](figures/dayu200/dayu200-wifi-09.png)
2737
2738Analyze the padding code of the MAC address. The MAC address is filled by **wpa_supplicant** based on the MAC address of p2p0. Therefore, the MAC address of the wdev object (p2p-dev-wlan0) is updated to the p2p0 API, and the two values must be the same. For details, see the call process of **wl_get_vif_macaddr(cfg, 7, p2p_hnetdev->macAddr)**.
2739
2740### Connection Success Log
2741
2742#### Connection Success Log in STA Mode
2743
2744```
2745WPA: Key negotiation completed with 50:eb:f6:02:8e6:d4 [PTK=CCMP GTK=CCMP]
2746 06 wlan0: State: GROUP_HANDSHAKEc -> COMPLETED
2747wlan0: CTRL-E4VENT-CONNECTED - Connection to 50:eb:f6:02:8e:d4 completed 3[id=0 id_str=]
2748WifiWpaReceived eEapol done
2749```
2750
2751#### Connection Success Log in AP Mode
2752
2753```
2754wlan0: STA 96:27:b3:95:b7:6e IEEE 802.1X: au:thorizing port
2755wlan0: STA 96:27:b3:95:b7:6e WPA: pairwise key handshake completed (RSN)
2756WifiWpaReceiveEapol done
2757```
2758
2759#### Connection Success Log in P2P Mode
2760
2761```
2762P2P: cli_channels:
2763EAPOL: External notificationtion - portValid=1
2764EAPOL: External notification:tion - EAP success=1
2765EAPOL: SUPP_PAE entering state AUTHENTIwCATING
2766EAPOL: SUPP_BE enterilng state SUCCESS
2767EAP: EAP ent_ering state DISABLED
2768EAPOL: SUPP_PAE entering state AUTHENTICATED
2769EAPOL:n Supplicant port status: Authoorized
2770EAPOL: SUPP_BE entertaining IDLE
2771WifiWpaReceiveEapol donepleted - result=SUCCESS
2772
2773\# ifconfig
2774
2775lo    Link encap:Local Loopback
2776     inet addr:127.0.0.1 Mask:255.0.0.0
2777     inet6 addr: ::1/128 Scope: Host
2778     UP LOOPBACK RUNNING MTU:65536 Metric:1
2779     RX packets:12 errors:0 dropped:0 overruns:0 frame:0
2780     TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
2781     collisions:0 txqueuelen:1000
2782     RX bytes:565 TX bytes:565
2783
2784wlan0   Link encap:Ethernet HWaddr 10:2c:6b:11:61:e0 Driver bcmsdh_sdmmc
2785     inet6 addr: fe80::122c:6bff:fe11:61e0/64 Scope: Link
2786     UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
2787     RX packets:0 errors:0 dropped:0 overruns:0 frame:0
2788     TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
2789     collisions:0 txqueuelen:1000
2790     RX bytes:0 TX bytes:0
2791
2792p2p0   Link encap:Ethernet HWaddr 12:2c:6b:11:61:e0
2793     inet6 addr: fe80::102c:6bff:fe11:61e0/64 Scope: Link
2794     UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
2795     RX packets:0 errors:0 dropped:0 overruns:0 frame:0
2796     TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
2797     collisions:0 txqueuelen:1000
2798     RX bytes:0 TX bytes:0
2799
2800p2p-p2p0-0 Link encap:Ethernet HWaddr 12:2c:6b:11:21:e0 Driver bcmsdh_sdmmc
2801     inet6 addr: fe80::102c:6bff:fe11:21e0/64 Scope: Link
2802     UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
2803     RX packets:0 errors:0 dropped:9 overruns:0 frame:0
2804     TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
2805     collisions:0 txqueuelen:1000
2806     RX bytes:0 TX bytes:0
2807```
2808
2809## Bluetooth
2810
2811### HCI API
2812
2813The overall Bluetooth hardware architecture consists of two parts: host (computer or MCU) and host controller (actual Bluetooth chipset). The communication between the host and controller complies with the HCI, as shown in the following figure.
2814
2815![dayu200-bt-01.png](figures/dayu200/dayu200-bt-01.png)
2816
2817HCI defines how to exchange commands, events, and asynchronous and synchronous packets. Asynchronous connectionless links (ACLs) are used for data transmission, while synchronous connection oriented links (SCOs) are used for voice with headsets and hands-free profiles.
2818
2819### Hardware Connection
2820
2821According to the description of the RK3568 chip, the RK3568 chip does not integrate the Wi-Fi/Bluetooth function. The RK3568 chip needs to connect to an external Bluetooth chip to support the Bluetooth function, which complies with the preceding logical architecture. Regarding the physical connection between the host and the controller, you can consult the development board specifications.
2822
2823![](figures/dayu200/dayu200-bt-02.png)
2824
2825Pins 28-36 are UART (serial port). In addition, several pins are used for power supply and hibernation control.
2826
2827### Bluetooth VENDORLIB Adaptation
2828
2829#### What Is vendorlib?
2830
2831vendorlib is deployed on the host, and may be considered as a Bluetooth chip driver layer on the host, to shield technical details of different Bluetooth chips. From the perspective of code, the main functions are as follows:
2832
28331. Provide a channel (file descriptor of the serial port) between Bluetooth chips for the protocol stack.
2834
28352. Provide specific control methods for specific chips.
2836
2837#### Interpretation of vendorlib at the Code Level
2838
2839**bt_vendor_lib.h**:
2840
2841```
2842foundation/communication/bluetooth/services/bluetooth_standard/hardware/include
2843```
2844
2845This file defines the interaction APIs between the protocol stack and **vendor_lib**, which are divided into two groups:
2846
28471. Implemented by vendorlib and called by the protocol stack
2848
2849```c
2850typedef struct {
2851    /**
2852     * Set to sizeof(bt_vendor_interface_t)
2853     */
2854    size_t size;
2855    /**
2856     * Caller will open the interface and pass in the callback routines
2857     * to the implementation of this interface.
2858     */
2859    int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char* local_bdaddr);
2860
2861    /**
2862     * Vendor specific operations
2863     */
2864    int (*op)(bt_opcode_t opcode, void* param);
2865
2866    /**
2867     * Closes the interface
2868     */
2869    void (*close)(void);
2870} bt_vendor_interface_t;
2871```
2872
2873The basic process of starting the protocol stack is as follows:
2874
28751.1. The protocol stack dynamically opens **libbt_vendor.z.so** and calls the **init** function to initialize **vendorlib**.
2876
28771.2. The protocol stack calls the OP function to call the OP codes **BT_OP_POWER_ON**, **BT_OP_HCI_CHANNEL_OPEN**, and **BT_OP_INIT**. In principle, if **BT_OP_INIT** is successful, the chip initialization is complete.
2878
28792. Implemented by the protocol stack and called by **vendorlib** (callback function)
2880
2881```c
2882typedef struct {
2883    /**
2884   * set to sizeof(bt_vendor_callbacks_t)
2885    */
2886    size_t size;
2887
2888    /* notifies caller result of init request */
2889    init_callback init_cb;
2890
2891    /* buffer allocation request */
2892    malloc_callback alloc;
2893
2894    /* buffer free request */
2895    free_callback dealloc;
2896
2897    /* hci command packet transmit request */
2898    cmd_xmit_callback xmit_cb;
2899} bt_vendor_callbacks_t;
2900```
2901
2902**init_cb** is called after **BT_OP_INIT** is complete.
2903
2904**alloc/dealloc** is used to apply for or release message controls when HCI messages are sent.
2905
2906**xmit_cb** sends HCI commands.
2907
2908Important functions implemented by **vendor_lib**:
2909
29101. **init** function
2911
2912```c
2913static int init(const bt_vendor_callbacks_t *p_cb, unsigned char *local_bdaddr)
2914{
2915     /* * ... */
2916    userial_vendor_init();
2917    upio_init();
2918
2919	vnd_load_conf(VENDOR_LIB_CONF_FILE);
2920
2921    /* store reference to user callbacks */
2922    bt_vendor_cbacks = (bt_vendor_callbacks_t *)p_cb;
2923        /* This is handed over from the stack */
2924    return memcpy_s(vnd_local_bd_addr, BD_ADDR_LEN, local_bdaddr, BD_ADDR_LEN);
2925}
2926```
2927
2928The **init** function is the first function called by **vendorlib**. **vendorlib** only needs to save the callback and MAC addresses of the protocol stack.
2929
29302. **BT_OP_POWER_ON**
2931
2932This operation needs to pull up the level of the power pin. In this function, the rfill device is used for processing, and the driver is not directly called to pull up the level.
2933
2934```c
2935int upio_set_bluetooth_power(int on)
2936{
2937    int sz;
2938    int fd = -1;
2939    int ret = -1;
2940    char buffer = '0';
2941
2942    switch (on) {
2943        case UPIO_BT_POWER_OFF:
2944            buffer = '0';
2945            break;
2946
2947        case UPIO_BT_POWER_ON:
2948            buffer = '1';
2949            break;
2950        default:
2951            return 0;
2952    }
2953
2954    /* check if we have rfkill interface */
2955    if (is_rfkill_disabled()) {
2956        return 0;
2957    }
2958
2959    if (rfkill_id == -1) {
2960        if (init_rfkill()) {
2961            return ret;
2962        }
2963    }
2964
2965    fd = open(rfkill_state_path, O_WRONLY);
2966    if (fd < 0) {
2967        return ret;
2968    }
2969
2970    sz = write(fd, &buffer, 1);
2971    /* ... */
2972    return ret;
2973}
2974```
2975
29763. **BT_OP_HCI_CHANNEL_OPEN** processing
2977
2978```c
2979case BT_OP_HCI_CHANNEL_OPEN: { // BT_VND_OP_USERIAL_OPEN
2980            int(*fd_array)[] = (int(*)[])param;
2981            int fd, idx;
2982            fd = userial_vendor_open((tUSERIAL_CFG *)&userial_init_cfg);
2983            if (fd != -1) {
2984                for (idx = 0; idx < HCI_MAX_CHANNEL; idx++)
2985                    (*fd_array)[idx] = fd;
2986                retval = 1;
2987        }
2988        /* retval contains numbers of open fd of HCI channels */
2989        break;
2990```
2991
2992The **userial_vendor_open** function opens the serial port device (UART) to obtain the file descriptor (FD). The FD is returned through the **param** parameter of OP.
2993
2994The name of the serial port device in the system must have been predefined in the development board. In this version, the device on the development board is **/dev/ttyS8**.
2995
29964. **BT_OP_INIT** processing
2997
2998The operation code requires initialization of the Bluetooth chip, and specific processing to be performed is closely related to the Bluetooth chip. The AP6257S chip used in this debugging is used as an example. During initialization, the Bluetooth firmware is delivered.
2999
3000After the initialization is complete, the **init_cb** callback function (see **bt_vendor_callbacks_t**) must be called to notify the protocol stack of the initialization result. Otherwise, the protocol stack thread is blocked and Bluetooth functions cannot be used properly. The protocol stack performs the following operations:
3001
3002After calling **BT_OP_INIT**, the protocol stack waits for the semaphore. The semaphore is set by the **init_cb** function.
3003
3004```c
3005static int HciInitHal()
3006{
3007    int result = BT_NO_ERROR;
3008
3009    g_waitHdiInit = SemaphoreCreate(0);
3010    int ret = g_hdiLib->hdiInit(&g_hdiCallbacks);
3011    if (ret == SUCCESS) {
3012        SemaphoreWait(g_waitHdiInit);
3013    }
3014}
3015```
3016
3017### vendorlib Porting Problem
3018
30191. Name of the .so file of vendorlib
3020
3021   The .so file name of vendorlib must be **libbt_vendor.z.so** because it is used when the protocol stack opens the dynamic link library (DLL).
3022
30232. Firmware problem
3024
3025   Pay attention to the chip firmware during development. The firmware of some Bluetooth chips may not need to be upgraded, but it's a must for some chips. During the adaptation of the AP6257S, the firmware is not delivered at the beginning. As a result, the received Bluetooth signals are poor. Pay attention to the following points when delivering firmware:
3026
3027   2.1. For the AP6257S chip, the Bluetooth chip does not have a flash memory. Therefore, the firmware must be delivered again after the chip is powered on and off.
3028
3029   2.2. The firmware is processed based on the chip requirements. It is recommended that the reference code of the vendor be found. Take the Broadcom series chips as an example. The firmware delivery process is complex and is driven by a state machine. There are nine states in total:
3030
3031```c
3032/ Hardware Configuration State */
3033enum {
3034  HW_CFG_START = 1,
3035  HW_CFG_SET_UART_CLOCK,
3036  HW_CFG_SET_UART_BAUD_1,
3037  HW_CFG_READ_LOCAL_NAME,
3038  HW_CFG_DL_MINIDRIVER,
3039  HW_CFG_DL_FW_PATCH,
3040  HW_CFG_SET_UART_BAUD_2,
3041  HW_CFG_SET_BD_ADDR,
3042  HW_CFG_READ_BD_ADDR
3043};
3044```
3045
3046Initialize the state machine after receiving the **BT_OP_INIT** message, send the **HCI_REST** command, and switch the state to **HW_CFG_START**.
3047
3048```c
3049void hw_config_start(void)
3050{
3051    HC_BT_HDR *p_buf = NULL;
3052    uint8_t *p;
3053    hw_cfg_cb.state = 0;
3054    hw_cfg_cb.fw_fd = -1;
3055    hw_cfg_cb.f_set_baud_2 = FALSE;
3056
3057    if (bt_vendor_cbacks) {
3058        p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE +
3059                                                     HCI_CMD_PREAMBLE_SIZE);
3060    }
3061
3062    if (p_buf) {
3063        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
3064        p_buf->offset = 0;
3065        p_buf->layer_specific = 0;
3066        p_buf->len = HCI_CMD_PREAMBLE_SIZE;
3067
3068        p = (uint8_t *)(p_buf + 1);
3069        UINT16_TO_STREAM(p, HCI_RESET);
3070        *p = 0;
3071
3072        hw_cfg_cb.state = HW_CFG_START;
3073        bt_vendor_cbacks->xmit_cb(HCI_RESET, p_buf);
3074    } else {
3075        if (bt_vendor_cbacks) {
3076            HILOGE("vendor lib fw conf aborted [no buffer]");
3077            bt_vendor_cbacks->init_cb(BTC_OP_RESULT_FAIL);
3078        }
3079    }
3080}
3081```
3082
3083After receiving the **HCI_RESET** completion event returned by the chip, the system switches to the next state machine and sends the next COMMAND until the state machine completes firmware delivery.
3084
3085For details, see the **hw_config_cback** function.
3086
30873. Pay attention to inter-system API differences.
3088
3089   The APIs may vary slightly by system, which requires special attention. For example, the definitions of the functions for **vendorlib** to call **xmit_cb** to send HCI commands are slightly different on different systems.
3090
3091Certain system:
3092
3093```c
3094/* define callback of the cmd_xmit_cb
3095 *
3096
3097The callback function which HCI lib will call with the return of command
3098
3099complete packet. Vendor lib is responsible for releasing the buffer passed
3100
3101in at the p_mem parameter by calling dealloc callout function.
3102*/
3103typedef void (*tINT_CMD_CBACK)(void* p_mem);
3104typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void* p_buf, tINT_CMD_CBACK p_cback);
3105```
3106
3107OpenHarmony:
3108
3109```c
3110/**
3111
3112hci command packet transmit callback
3113
3114Vendor lib calls cmd_xmit_cb function in order to send a HCI Command
3115
3116packet to BT Controller.
3117*
3118
3119The opcode parameter gives the HCI OpCode (combination of OGF and OCF) of
3120
3121HCI Command packet. For example, opcode = 0x0c03 for the HCI_RESET command
3122
3123packet. */
3124
3125typedef uint8_t (*cmd_xmit_callback)(uint16_t opcode, void* p_buf);
3126```
3127
3128As shown above, after a command is sent in vendorlib, the certain system notifies the chip of the returned message through a callback, while OpenHarmony notifies the chip of the returned message through the **BT_OP_EVENT_CALLBACK** operation code (see the definition of **bt_opcode_t**). vendorlib needs to parse the message code in the packet to determine which message is to be processed by the chip, and then calls the corresponding processing function.
3129
3130```c
3131void hw_process_event(HC_BT_HDR *p_buf)
3132{
3133    uint16_t opcode;
3134    uint8_t *p = (uint8_t *)(p_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
3135    STREAM_TO_UINT16(opcode, p);
3136    switch (opcode) {
3137    case HCI_VSC_WRITE_BD_ADDR:
3138    #if (USE_CONTROLLER_BDADDR == TRUE)
3139        case HCI_READ_LOCAL_BDADDR:
3140    #endif
3141        case HCI_READ_LOCAL_NAME:
3142        case HCI_VSC_DOWNLOAD_MINIDRV:
3143        case HCI_VSC_WRITE_FIRMWARE:
3144        case HCI_VSC_LAUNCH_RAM:
3145        case HCI_RESET:
3146        case HCI_VSC_WRITE_UART_CLOCK_SETTING:
3147        case HCI_VSC_UPDATE_BAUDRATE:
3148            hw_config_cback(p_buf);
3149            break;
3150```
3151
3152The returned messages are also different. OpenHarmony returns the number of bytes in the message. If the value is less than or equal to **0**, the message fails to be sent.
3153
31544. snoop log
3155
3156   Like other systems, OpenHarmony logs HCI records, which are saved in the **/data/log/bluetooth/snoop.log** file. This allows you to use Wireshark or other packet analysis tools to examine the interaction process between the host and controller, facilitating fault analysis.
3157
3158##    Sensor
3159
3160  Sensor driver model developed based on the HDF driver framework
3161
3162![dayu200-sensor-01.png](figures/dayu200/dayu200-sensor-01.png)
3163
3164RK3568 supports the accel sensor. The OpenHarmony mainline version has the overall driver framework. You only need to implement the specific component driver.
3165
3166### Implementation of the mcx5566xa HDF Driver
3167
3168The RK3568 platform supports the acceleration sensor MXC6655XA. For details about the configuration, see the datasheet of the acceleration sensor. Before porting the HDF, ensure that the compilation of the sensor in the kernel is disabled.
3169
3170The configuration file is stored in **kernel/linux/config/linux-5.10/arch/arm64/configs/rk3568_standard_defconfig**.
3171
3172```c
3173# CONFIG_GS_MXC6655XA is not set
3174```
3175
3176Code path:
3177
3178```c
3179drivers/framework/model/sensor/driver/chipset/accel/accel_mxc6655xa.c
3180drivers/framework/model/sensor/driver/chipset/accel/accel_mxc6655xa.h
3181```
3182
3183Compile the macros.
3184
3185```c
3186CONFIG_DRIVERS_HDF_SENSOR_ACCEL_MXC6655XA=y
3187```
3188
3189Implementation of the MXC6655XA accelerometer driver entry function
3190
3191```c
3192struct HdfDriverEntry g_accelMxc6655xaDevEntry = {
3193    .moduleVersion = 1,
3194    .moduleName = "HDF_SENSOR_ACCEL_MXC6655XA",
3195    .Bind = Mxc6655xaBindDriver,
3196    .Init = Mxc6655xaInitDriver,
3197    .Release = Mxc6655xaReleaseDriver,
3198};
3199
3200HDF_INIT(g_accelMxc6655xaDevEntry);
3201```
3202
3203Next, let's look at the differentiated adaptation function.
3204
3205```c
3206struct AccelOpsCall {
3207int32_t (*Init)(struct SensorCfgData *data);
3208int32_t (*ReadData)(struct SensorCfgData *data);
3209};
3210```
3211
3212API for obtaining data on the X, Y, and Z axises:
3213
3214```c
3215int32_t ReadMxc6655xaData(struct SensorCfgData *cfg, struct SensorReportEvent *event)
3216{
3217    int32_t ret;
3218    struct AccelData rawData = { 0, 0, 0 };
3219    static int32_t tmp[ACCEL_AXIS_NUM];
3220
3221    CHECK_NULL_PTR_RETURN_VALUE(cfg, HDF_ERR_INVALID_PARAM);
3222    CHECK_NULL_PTR_RETURN_VALUE(event, HDF_ERR_INVALID_PARAM);
3223
3224    ret = ReadMxc6655xaRawData(cfg, &rawData, &event->timestamp);
3225    if (ret != HDF_SUCCESS) {
3226        HDF_LOGE("%s: MXC6655XA read raw data failed", __func__);
3227        return HDF_FAILURE;
3228    }
3229
3230    event->sensorId = SENSOR_TAG_ACCELEROMETER;
3231    event->option = 0;
3232    event->mode = SENSOR_WORK_MODE_REALTIME;
3233
3234    rawData.x = rawData.x * MXC6655XA_ACC_SENSITIVITY_2G;
3235    rawData.y = rawData.y * MXC6655XA_ACC_SENSITIVITY_2G;
3236    rawData.z = rawData.z * MXC6655XA_ACC_SENSITIVITY_2G;
3237
3238    tmp[ACCEL_X_AXIS] = (rawData.x * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;
3239    tmp[ACCEL_Y_AXIS] = (rawData.y * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;
3240    tmp[ACCEL_Z_AXIS] = (rawData.z * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;
3241
3242    ret = SensorRawDataToRemapData(cfg->direction, tmp, sizeof(tmp) / sizeof(tmp[0]));
3243    if (ret != HDF_SUCCESS) {
3244        HDF_LOGE("%s: MXC6655XA convert raw data failed", __func__);
3245        return HDF_FAILURE;
3246    }
3247
3248    event->dataLen = sizeof(tmp);
3249    event->data = (uint8_t *)&tmp;
3250
3251    return ret;
3252}
3253```
3254
3255Initialization:
3256
3257```c
3258static int32_t InitMxc6655xa(struct SensorCfgData *data)
3259{
3260    int32_t ret;
3261
3262    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
3263    ret = SetSensorRegCfgArray(&data->busCfg, data->regCfgGroup[SENSOR_INIT_GROUP]);
3264    if (ret != HDF_SUCCESS) {
3265        HDF_LOGE("%s: MXC6655XA sensor init config failed", __func__);
3266        return HDF_FAILURE;
3267    }
3268    return HDF_SUCCESS;
3269}
3270```
3271
3272### HCS Configuration
3273
3274HCS configuration of the MXC6655XA accel sensor driver:
3275
3276```c
3277device_sensor_mxc6655xa :: device {
3278    device0 :: deviceNode {
3279        policy = 1;
3280        priority = 120;
3281        preload = 0;
3282        permission = 0664;
3283        moduleName = "HDF_SENSOR_ACCEL_MXC6655XA";
3284        serviceName = "hdf_accel_mxc6655xa";
3285        deviceMatchAttr = "hdf_sensor_accel_mxc6655xa_driver";
3286    }
3287}
3288```
3289
3290Register group configuration information of the MXC6655XA accel sensor:
3291
3292```c
3293#include "../sensor_common.hcs"
3294root {
3295    accel_mxc6655xa_chip_config : sensorConfig {
3296        match_attr = "hdf_sensor_accel_mxc6655xa_driver";
3297        sensorInfo :: sensorDeviceInfo {
3298            sensorName = "accelerometer";
3299            vendorName = "memsi_mxc6655xa"; // max string length is 16 bytes
3300            sensorTypeId = 1; // enum SensorTypeTag
3301            sensorId = 1; // user define sensor id
3302            power = 230;
3303        }
3304        sensorBusConfig :: sensorBusInfo {
3305            busType = 0; // 0:i2c 1:spi
3306            busNum = 5;
3307            busAddr = 0x15;
3308            regWidth = 1; // 1byte
3309        }
3310        sensorIdAttr :: sensorIdInfo {
3311            chipName = "mxc6655xa";
3312            chipIdRegister = 0x0f;
3313            chipIdValue = 0x05;
3314        }
3315        sensorDirection {
3316            direction = 5; // chip direction range of value:0-7
3317            /* <sign> 1:negative  0:positive
3318               <map> 0:AXIS_X  1:AXIS_Y  2:AXIS_Z
3319            */
3320            /* sign[AXIS_X], sign[AXIS_Y], sign[AXIS_Z], map[AXIS_X], map[AXIS_Y], map[AXIS_Z] */
3321            convert = [
3322                0, 0, 0, 0, 1, 2,
3323                1, 0, 0, 1, 0, 2,
3324                0, 0, 1, 0, 1, 2,
3325                0, 1, 0, 1, 0, 2,
3326                1, 0, 1, 0, 1, 2,
3327                0, 0, 1, 1, 0, 2,
3328                0, 1, 1, 0, 1, 2,
3329                1, 1, 1, 1, 0, 2
3330            ];
3331        }
3332        sensorRegConfig {
3333            /*  regAddr: register address
3334                value: config register value
3335                len: size of value
3336                mask: mask of value
3337                delay: config register delay time (ms)
3338                opsType: enum SensorOpsType 0-none 1-read 2-write 3-read_check 4-update_bit
3339                calType: enum SensorBitCalType 0-none 1-set 2-revert 3-xor 4-left shift 5-right shift
3340                shiftNum: shift bits
3341                debug: 0-no debug 1-debug
3342                save: 0-no save 1-save
3343            */
3344            /* regAddr, value, mask, len, delay, opsType, calType, shiftNum, debug, save */
3345            initSeqConfig = [
3346                0x7e,    0xb6, 0xff,   1,     5,       2,       0,        0,     0,    0,
3347                0x7e,    0x10, 0xff,   1,     5,       2,       0,        0,     0,    0
3348            ];
3349            enableSeqConfig = [
3350                0x7e,    0x11, 0xff,   1,     5,       2,       0,        0,     0,    0,
3351                0x41,    0x03, 0xff,   1,     0,       2,       0,        0,     0,    0,
3352                0x40,    0x08, 0xff,   1,     0,       2,       0,        0,     0,    0
3353            ];
3354            disableSeqConfig = [
3355                0x7e,    0x10, 0xff,   1,     5,       2,       0,        0,     0,    0
3356            ];
3357        }
3358    }
3359}
3360```
3361
3362### Testing
3363
3364The three-axis data of the sensor can be obtained during the UT test.
3365
3366Test code path:
3367
3368```c
3369drivers/peripheral/sensor/test/unittest/common/hdf_sensor_test.cpp
3370```
3371
3372Build UT code:
3373
3374```c
3375./build.sh --product-name rk3568 --build-target hdf_test_sensor
3376```
3377
3378Push **hdf_test_sensor.bin** to the **system/bin** directory, add the execute permission to the file, and execute the file.
3379
3380If the following information is displayed, the sensor test is successful.
3381
3382```c
3383SensorTestDataCallback enter
3384sensor id :[1], data[1]: 0.001877
3385sensor id :[1], data[2]: 0.160823
3386sensor id :[1], data[3]: 0.046122
3387```
3388
3389##    Vibrator
3390
3391### Vibrator Model
3392
3393The vibrator driver model provides and implements vibrator-related HDIs. It supports the time sequence configuration in the static HCS and the duration configuration through dynamic parameters. The vibrator hardware service calls **StartOnce** to start one-shot vibration for a given duration and calls **StartEffect** to start vibration with a specified effect.
3394
3395**Figure 1** Architecture of the vibrator driver module
3396
3397![dayu200-vibrator-01.png](figures/dayu200/dayu200-vibrator-01.png)
3398
3399The RK3568 supports the linear vibrator. The OpenHarmony mainline version has the overall driver framework. You only need to implement the specific component driver.
3400
3401### HDF Driver Implementation
3402
3403Code path:
3404
3405```c
3406drivers/framework/model/misc/vibrator/driver/chipset/vibrator_linear_driver.c
3407```
3408
3409Implementation of the linear vibrator accelerometer driver entry function:
3410
3411```c
3412struct HdfDriverEntry g_linearVibratorDriverEntry = {
3413    .moduleVersion = 1,
3414    .moduleName = "HDF_LINEAR_VIBRATOR",
3415    .Bind = BindLinearVibratorDriver,
3416    .Init = InitLinearVibratorDriver,
3417    .Release = ReleaseLinearVibratorDriver,
3418};
3419
3420HDF_INIT(g_linearVibratorDriverEntry);
3421```
3422
3423### HCS Configuration
3424
3425HCS configuration of the driver:
3426
3427```c
3428        vibrator :: host {
3429            hostName = "vibrator_host";
3430            device_vibrator :: device {
3431                device0 :: deviceNode {
3432                    policy = 2;
3433                    priority = 100;
3434                    preload = 0;
3435                    permission = 0664;
3436                    moduleName = "HDF_VIBRATOR";
3437                    serviceName = "hdf_misc_vibrator";
3438                    deviceMatchAttr = "hdf_vibrator_driver";
3439                }
3440            }
3441            device_linear_vibrator :: device {
3442                device0 :: deviceNode {
3443                    policy = 1;
3444                    priority = 105;
3445                    preload = 0;
3446                    permission = 0664;
3447                    moduleName = "HDF_LINEAR_VIBRATOR";
3448                    serviceName = "hdf_misc_linear_vibrator";
3449                    deviceMatchAttr = "hdf_linear_vibrator_driver";
3450                }
3451            }
3452        }
3453```
3454
3455HCS configuration of the linear vibrator:
3456
3457```c
3458root {
3459    linearVibratorConfig {
3460        boardConfig {
3461            match_attr = "hdf_linear_vibrator_driver";
3462            vibratorChipConfig {
3463                busType = 1; // 0:i2c 1:gpio
3464                gpioNum = 154;
3465                startReg = 0;
3466                stopReg = 0;
3467                startMask = 0;
3468            }
3469        }
3470    }
3471}
3472```
3473
3474### UT Test
3475
3476Test code path:
3477
3478```c
3479drivers/peripheral/misc/vibrator/test/unittest/common/hdf_vibrator_test.cpp
3480```
3481
3482Build UT code:
3483
3484```c
3485./build.sh --product-name rk3568 --build-target hdf_test_vibrator
3486```
3487
3488Push **hdf_test_vibrator.bin** to the **system/bin** directory, add the execute permission to the file, and execute the file.
3489
3490```
3491[ RUN ] HdfVibratorTest.CheckVibratorInstanceIsEmpty
3492[ OK ] HdfVibratorTest.CheckVibratorInstanceIsEmpty (0 ms)
3493[ RUN ] HdfVibratorTest.PerformOneShotVibratorDuration001
3494[ OK ] HdfVibratorTest.PerformOneShotVibratorDuration001 (2001 ms)
3495[ RUN ] HdfVibratorTest.ExecuteVibratorEffect001
3496[ OK ] HdfVibratorTest.ExecuteVibratorEffect001 (5001 ms)
3497```
3498