• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 物联网解决方案之芯海cst85芯片移植案例
2
3本文介绍基于芯海cst85芯片的cst85_wblink开发板移植OpenHarmony LiteOS-M轻量系统的移植案例。开发了Wi-Fi连接样例和XTS测试样例,同时实现了wifi_lite, lwip, startup, utils, xts, hdf等部件基于OpenHarmony LiteOS-M内核的适配。移植架构上采用Board和Soc分离的方案,工具链采用NewLib C库,LiteOS-M内核编译采用gn结合Kconfig图形化配置的方式。
4
5## 编译构建适配
6
7### 目录规划
8
9本方案目录结构使用[Board和SoC解耦的设计思路](https://gitee.com/openharmony-sig/sig-content/blob/master/devboard/docs/board-soc-arch-design.md)10
11```
12device
13├── board                                --- 单板厂商目录
14│   └── chipsea                          --- 单板厂商名字:芯海科技
15│       └── cst85_wblink                 --- 单板名:cst85_wblink
16└── soc                                  --- SoC厂商目录
17    └── chipsea                          --- SoC厂商名字:芯海科技
18        └── cst85                        --- SoC Series名:cst85
19```
20
21产品样例目录规划为:
22
23```
24vendor
25└── chipsea                              --- 开发产品样例厂商目录,芯海科技的产品样例
26    ├── iotlink_demo                     --- 产品名字:Wi-Fi样例
27    └── xts_demo                         --- 产品名字:XTS测试样例
28```
29
30### 产品定义
31vendor/chipsea/iotlink_demo为例,这里描述了产品使用的内核、单板、子系统等信息。其中,内核、单板型号、单板厂商需要提前规划好,也是预编译指令所关注的信息。这里填入的信息与规划的目录相对应。例如:
32```
33{
34  "product_name": "iotlink_demo",        --- 产品名
35  "version": "3.0",                      --- 系统版本:3.0
36  "device_company": "chipsea",           --- 单板厂商:chipsea
37  "board": "cst85_wblink",               --- 单板名:cst85_wblink
38  "kernel_type": "liteos_m",             --- 内核类型:liteos_m
39  "kernel_version": "3.0.0",             --- 内核版本:3.0.0
40  "subsystems": []                       --- 子系统
41}
42```
43
44### 单板配置
45在产品定义关联到的目录下,以/device/board/chipsea/cst85_wblink为例,需要在liteos_m目录下放置config.gni文件,这个配置文件用于描述该单板的信息,包括cpu, toolchain, kernel, compile_flags等。例如:
46```
47# 内核类型。
48kernel_type = "liteos_m"
49
50# 内核版本。
51kernel_version = "3.0.0"
52
53# 单板CPU类型。
54board_cpu = "cortex-m4"
55
56# 工具链,这里使用arm-none-eabi。
57board_toolchain = "arm-none-eabi"
58
59# 工具链路径,可以使用系统路径,填"",也可以自定义,如下:
60board_toolchain_path = ""
61
62# 单板相关的编译参数。
63board_cflags = []
64
65# 单板相关的链接参数。
66board_ld_flags = []
67
68# 单板相关的头文件。
69board_include_dirs = []
70
71# Board adapter dir for OHOS components.
72board_adapter_dir = "${ohos_root_path}device/soc/chipsea"
73```
74
75### 预编译
76在正确配置好产品的目录、产品定义、单板配置后,在工程根目录下输入预编译指令hb set,在显示的列表中就可以找到相关的产品。
77
78![ohos_config.json](figures/cst85_hb_set.png)
79
80选择好产品后,输入回车就会在根目录下自动生成`ohos_config.json`文件,这里会列出待编译的产品信息:
81
82```
83{
84  "root_path": "/home/openharmony",
85  "board": "cst85_wblink",
86  "kernel": "liteos_m",
87  "product": "iotlink_demo",
88  "product_path": "/home/openharmony/vendor/chipsea/iotlink_demo",
89  "device_path": "/home/openharmony/device/board/chipsea/cst85_wblink/liteos_m",
90  "device_company": "chipsea",
91  "os_level": "mini",
92  "version": "3.0",
93  "patch_cache": null,
94  "product_json": "/home/openharmony/vendor/chipsea/iotlink_demo/config.json",
95  "target_cpu": null,
96  "target_os": null,
97  "out_path": "/home/openharmony/out/cst85_wblink/iotlink_demo"
98}
99```
100
101
102## 内核移植
103
104### Kconfig适配
105
106在//kernel/liteos_m的编译中,需要在相应的单板以及SoC目录下使用`Kconfig`文件进行配置。我们分别来看一下单板和Soc目录下的相关配置。
107
108单板目录的`Kconfig`,以`//device/board/chipsea`为例:
109```
110device/board/chipsea
111├── cst85_wblink                                 --- cst85_wblink单板配置目录
112│   ├── Kconfig.liteos_m.board                   --- 单板的配置选项
113│   ├── Kconfig.liteos_m.defconfig.board         --- 单板的默认配置项
114│   └── liteos_m
115│       └── config.gni                           --- 单板的配置文件
116├── Kconfig.liteos_m.boards                      --- 单板厂商下Boards配置信息
117└── Kconfig.liteos_m.defconfig.boards            --- 单板厂商下Boards配置信息
118```
119
120在 `cst85_wblink/Kconfig.liteos_m.board`中,配置只有SOC_CST85F01被选后,BOARD_CST85_WBLINK才可被选:
121```
122config BOARD_CST85_WBLINK
123    bool "select board cst85_wblink"
124    depends on SOC_CST85F01
125```
126
127SoC目录的`Kconfig`,以`//device/soc/chipsea`为例:
128
129```
130device/soc/chipsea/
131├── cst85                                        --- cst85系列
132│   ├── Kconfig.liteos_m.defconfig.cst85f01      --- cst85f01芯片默认配置
133│   ├── Kconfig.liteos_m.defconfig.series        --- cst85系列芯片默认配置
134│   ├── Kconfig.liteos_m.series                  --- cst85系列配置
135│   └── Kconfig.liteos_m.soc                     --- cst85芯片配置
136├── Kconfig.liteos_m.defconfig                   --- SoC默认配置
137├── Kconfig.liteos_m.series                      --- Series配置
138└── Kconfig.liteos_m.soc                         --- SoC配置
139```
140
141`cst85/Kconfig.liteos_m.series`配置如下:
142
143```
144config SOC_SERIES_CST85
145    bool "Chipsea CST85 Series"
146    select ARM
147    select SOC_COMPANY_CHIPSEA
148    select CPU_CORTEX_M4
149    help
150        Enable support for Chipsea CST85 series
151```
152
153只有选择了 SOC_SERIES_CST85,在 cst85/Kconfig.liteos_m.soc中才可以选择SOC_CST85F01:
154
155```
156choice
157    prompt "Chipsea CST85 series SoC"
158    depends on SOC_SERIES_CST85
159
160config SOC_CST85F01
161    bool "SoC CST85F01"
162
163endchoice
164```
165
166综上所述,要编译单板BOARD_CST85_WBLINK,则要分别选中:SOC_COMPANY_CHIPSEA、SOC_SERIES_CST85、SOC_CST85F01,可以在`kernel/liteos_m`中执行`make menuconfig`进行选择配置。
167
168![cst85_kconfig.json](figures/cst85_kconfig.png)
169
170配置后的文件会默认保存在`//vendor/chipsea/iotlink_demo/kernel_configs/debug.config`,也可以直接填写debug.config171
172```
173LOSCFG_SOC_SERIES_CST85=y
174LOSCFG_KERNEL_BACKTRACE=y
175LOSCFG_KERNEL_CPUP=y
176LOSCFG_PLATFORM_EXC=y
177```
178
179### 模块化编译
180
181`Board`和`SoC`的编译采用模块化的编译方法,从`kernel/liteos_m/BUILD.gn`开始逐级向下递增。本方案的适配过程如下:
182
1831. 在`//device/board/chipsea`中新建文件BUILD.gn,新增内容如下:
184
185   ```
186   if (ohos_kernel_type == "liteos_m") {
187     import("//kernel/liteos_m/liteos.gni")
188     module_name = get_path_info(rebase_path("."), "name")
189     module_group(module_name) {
190       modules = [
191         "cst85_wblink"
192       ]
193     }
194   }
195   ```
196
197   在上述BUILD.gn中,cst85_wblink即是按目录层级组织的模块名。
198
1992. 在`//device/soc/chipsea`中,使用同样的方法,新建文件BUILD.gn,按目录层级组织,新增内容如下:
200
201   ```
202   if (ohos_kernel_type == "liteos_m") {
203     import("//kernel/liteos_m/liteos.gni")
204     module_name = get_path_info(rebase_path("."), "name")
205     module_group(module_name) {
206       modules = [
207         "cst85",
208         "hals",
209       ]
210     }
211   }
212   ```
213
2143. 在`//device/soc/chipsea`各个层级模块下,同样新增文件BUILD.gn,将该层级模块加入编译,以`//device/soc/chipsea/cst85/liteos_m/sdk/bsp/arch/BUILD.gn`为例:
215
216   ```
217   import("//kernel/liteos_m/liteos.gni")
218   module_name = "sdk_bsp_arch"
219
220   kernel_module(module_name) {
221     sources = [
222       "boot/armgcc_4_8/boot_startup.S",
223       "boot/armgcc_4_8/exception.S",
224       "boot/fault_handler.c",
225
226       "cmsis/cmsis_nvic.c",
227
228       "ll/ll.c",
229
230       "main/arch_main.c",
231     ]
232
233     include_dirs = [
234       "boot",
235       "boot/armgcc_4_8",
236     ]
237
238     deps = [
239       "//base/startup/bootstrap_lite/services/source:bootstrap",
240     ]
241   }
242
243   config("public") {
244     include_dirs = [
245       ".",
246       "boot",
247       "compiler",
248       "cmsis",
249       "ll",
250     ]
251   }
252   ```
253
254   其中,为了组织链接以及一些编译选项,在config("public")填入了相应的参数:
255
256   ```
257   config("public") {
258     include_dirs = []                       --- 公共头文件
259     ldflags = []                            --- 链接参数,包括ld文件
260     libs = []                               --- 链接库
261     defines = []                            --- 定义
262   }
263   ```
264
265   ![](../public_sys-resources/icon-note.gif) **说明:**
266	建议公共的参数选项以及头文件不在各个组件中重复填写。
267
268### 内核启动适配
269
270内核启动适配的文件路径在 `//device/soc/chipsea/cst85/liteos_m/sdk/modules/rtos/src/rtos.c`
271
272内核启动适配总体思路如下:
273
2741. 中断向量的初始化`   OsVectorInit();` ,初始化中断的处理函数。
2752. 内核初始化`osKernelInitialize` 。
2763. 创建线程`OHOS_SystemInit`OS组件平台初始化。
2774. `DeviceManagerStart(); HDF 初始化`。
2785. 内核启动,开始调度线程`LOS_Start` 。
279
280其中,本章节详细对第3步进行展开,其他几步为对内核函数调用,不作详细描述。
281
282第3步中在启动`OHOS_SystemInit`之前,需要初始化必要的动作,如下:
283
284```
285...
286    LOS_KernelInit();
287    DeviceManagerStart();
288    OHOS_SystemInit();
289    LOS_Start();
290
291....
292```
293
294### 中断适配
295要使LiteOS-M系统正常的运转起来,有两个中断服务线程必须重定向到LiteOS-M指定的ISR:HalPendSV和OsTickerHandler。而这取决于适配LiteOS-M系统时是否让LiteOS-M来接管中断向量表。
296```
297/**
298 * @ingroup los_config
299 * Configuration item for using system defined vector base address and interrupt handlers.
300 * If LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT is set to 0, vector base address will not be
301 * modified by system. In arm, it should be noted that PendSV_Handler and SysTick_Handler should
302 * be redefined to HalPendSV and OsTickHandler respectably in this case, because system depends on
303 * these interrupt handlers to run normally. What's more, LOS_HwiCreate will not register handler.
304 */
305#ifndef LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT
306#define LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT                 1
307#endif
308```
309
310#### 操作系统是否接管中断向量
311LiteOS接管与否可以通过配置target_config.h中的配置来实现。1接管,0不接管。
312```
313#define LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT                 0
314```
315
316
317如果配置为1,这时LiteOS会修改SCB->VTOR为g_hwiForm。所以需要在启动的时候通过调用LITEOS的"ArchHwiCreate"接口把芯片原先的ISRs(中断服务程序)配置到新的中断向量表g_hwiForm中去, 而PendSV和SysTicke的中断服务线程则重定向到HalPendSV和OsTickerHandler。否则芯片原先的ISRs不会响应。
318
319如果配置为0,则使用芯片原有的中断向量表,对于CST85F01而言就是__vectors_start___(NVIC_Vectors_Init会把__isr_vector的内容拷贝过来)。但要想适配LITEOS的话,必须把PendSV和SysTick的中断服务程序重定向到HalPendSV和OsTickHandler才行,否则系统跑不起来。
320
321我们这里选择不让LITEOS接管中断处理,为此我们需要在启动的时候,重定向PendSV和SysTick的中断服务程序到HalPendSV和OsTickHandler:
322```
323#ifdef CFG_LITEOS
324static void OsVectorInit(void)
325{
326    NVIC_SetVector(PendSV_IRQn, (uint32_t)HalPendSV);
327    NVIC_SetVector(SysTick_IRQn, (uint32_t)OsTickHandler);
328}
329#endif
330```
331
332#### 中断向量表地址对齐
333在Cortex-M的相关文档已经说明,中断向量表的地址最小是32字对齐,也就是0x80。
334举例来说,如果需要21个中断,因为系统中断有16个,所以总共就有37个中断,需要37\*4个表项,一个0x80已经不够了,需要两个0x80,也就是0x100才能覆盖的住。
335
336而在cst85f01的适配中,我们的中断向量LIMIT为128个(target_config.h中定义的):
337```
338#define LOSCFG_PLATFORM_HWI_LIMIT                           128
339```
340我们需要128个中断,加上系统中断,总共(128+16)=144个中断,需要144\*4个表项,这些表项总共需要4个0x80才能盖的住,也即必须是0x200对齐才行。否则,会出现系统重启的现象。
341为此,我们需要把中断对齐覆盖为0x200:
342```
343#ifndef LOSCFG_ARCH_HWI_VECTOR_ALIGN
344#define LOSCFG_ARCH_HWI_VECTOR_ALIGN                         0x200
345#endif
346```
347
348### littlefs文件系统适配
349
350XTS测试中的syspara的测试对kv的存储涉及到文件的读写,所以需要适配一个文件系统,来让kv存储到flash的某个区间位置。为此,我们进行了littlefs文件系统的适配工作。
351
352适配过程中,需要在`device/soc/chipsea/cst85/liteos_m/components/drivers/littlefs`增加适配接口。
353
354```
355  #define LFS_DEFAULT_START_ADDR 0x081E3000 ---littlefs 起始地址
356  #define LFS_DEFAULT_BLOCK_SIZE 4096       ---块大小
357  #define LFS_DEFAULT_BLOCK_COUNT 25        ---块数量
358
359```
360
361最后在`device/soc/chipsea/cst85/liteos_m/components/drivers/littlefs/hal_vfs.c`中对kernel的littlefs接口进行实现。
362
363```
364int32_t hal_vfs_init(void)
365{
366    VfsOps = malloc(sizeof(struct lfs_manager));
367    if (VfsOps == NULL) {
368        printf("+++ hal_vfs_init: NO memory!!\n");
369        return -1;
370    } else {
371        memset(VfsOps, 0, sizeof(struct lfs_manager));
372    }
373
374    VfsOps->LfsOps.read = lfs_block_read; //read flash 接口。
375    VfsOps->LfsOps.prog = lfs_block_write; //write flash 接口。
376    VfsOps->LfsOps.erase = lfs_block_erase; //erase flash 接口。
377    VfsOps->LfsOps.sync = lfs_block_sync;
378    VfsOps->LfsOps.read_size = 256;
379    VfsOps->LfsOps.prog_size = 256;
380    VfsOps->LfsOps.cache_size = 256;
381    VfsOps->LfsOps.lookahead_size = 16;
382    VfsOps->LfsOps.block_cycles = 500;
383    VfsOps->start_addr = LFS_DEFAULT_START_ADDR;
384    VfsOps->LfsOps.block_size = LFS_DEFAULT_BLOCK_SIZE;
385    VfsOps->LfsOps.block_count = LFS_DEFAULT_BLOCK_COUNT;
386
387    SetDefaultMountPath(0,"/data");
388    if (LOS_FsMount(NULL, "/data", "littlefs", 0, VfsOps) != FS_SUCCESS) {
389        printf("+++ hal_vfs_init: Mount littlefs failed!\n");
390        free(VfsOps);
391        return -1;
392    }
393
394    if (LOS_Mkdir("/data", 0777) != 0 ) {
395        printf("+++ hal_vfs_init: Make dir failed!\n");
396    }
397
398    flash_user_data_addr_length_set(LFS_DEFAULT_START_ADDR,
399            LFS_DEFAULT_BLOCK_SIZE * LFS_DEFAULT_BLOCK_COUNT);
400
401    printf("+++ hal_vfs_init: Mount littlefs success!\n");
402    return 0;
403}
404
405```
406
407
408
409### C库适配
410
411在轻量系统中,C库适配比较复杂,设计思路请参考[LiteOS-M内核支持musl与newlib平滑切换方案](https://gitee.com/arvinzzz/ohos_kernel_design_specification/blob/master/liteos_m/%E6%94%AF%E6%8C%81newlib/%E5%86%85%E6%A0%B8%E9%80%82%E9%85%8Dnewlib%E6%96%B9%E6%A1%88%E6%80%9D%E8%B7%AF.md),自带`newlib`的C库,那么系统移植整体采用`newlib`的C库。在`vendor/chipsea/iotlink_demo/kernel_configs/debug.config`选中LOSCFG_LIBC_NEWLIB=y即可。
412
413
414### printf适配
415
416要想让开发者方便的使用C库中的标准函数来输出信息,就需要进行相应的适配,把标准函数要输出的信息输出到我们的硬件(我们这里就是串口)。为此,我们进行了printf函数的适配。
417
418在`//device/board/chipsea/cst85_wblink/liteos_m/config.gni`的新增printf函数的`wrap`链接选项。
419
420```
421board_ld_flags += [
422     "-Wl,--wrap=printf",
423]
424```
425
426在`device/soc/chipsea/cst85/liteos_m/sdk/bsp/wrapper/lite_sys.c`中对"__wrap_printf"进行了实现。
427
428
429### GPIO的HDF适配
430为了让开发者方便的使用HDF框架来使用GPIO的功能,我们对GPIO进行了HDF框架的适配。
431
4321. 芯片驱动适配文件位于`//drivers/adapter/platform`目录,在gpio目录增加gpio_chipsea.cgpio_chipsea.h文件,在BUILD.gn中增加新增的驱动文件编译条件:
433
434   ```
435   if (defined(LOSCFG_SOC_COMPANY_CHIPSEA)) {
436    sources += [ "gpio_chipsea.c" ]
437   }
438   ```
439
4402. gpio_chipsea.c中驱动描述文件如下:
441
442   ```
443   struct HdfDriverEntry g_gpioDriverEntry = {
444       .moduleVersion = 1,
445       .moduleName = "HDF_PLATFORM_GPIO",
446       .Bind = GpioDriverBind,
447       .Init = GpioDriverInit,
448       .Release = GpioDriverRelease,
449   };
450
451   HDF_INIT(g_gpioDriverEntry);
452   ```
453
4543. 在cst85/liteos_m/components/hdf_config/device_info.hcs`添加gpio硬件描述信息文件gpio.hcs, 映射后的gpio0控制板卡上的可编程LED,hcs内容如下:
455
456   ```
457   root {
458       platform :: host {
459            hostName = "platform_host";
460            priority = 50;
461            device_gpio :: device {
462                gpio0 :: deviceNode {
463                    policy = 0;
464                    priority = 100;
465                    moduleName = "HDF_PLATFORM_GPIO";
466                    serviceName = "HDF_PLATFORM_GPIO";
467                    deviceMatchAttr = "gpio_config";
468            }
469       }
470   }
471   ```
472
473
474## OpenHarmony子系统适配
475
476### 通信子系统
477
478在通信子系统中,我们需要打开wifi_lite组件,并适配与之相关的各个接口。
479
480wifi_lite组件的选项配置如下:
481
482```
483"subsystem": "communication",
484"components": [
485  { "component": "wifi_lite", "features":[] }
486  ]
487```
488
489与Wi-Fi有关的实现在`//device/soc/chipsea/hals/communication/wifi_lite/wifiservice/wifi_device.c`下。
490
491```
492……
493WifiErrorCode Scan(void)
494{
495    WIFI_STATE_INVALID_CHECK(WIFI_INACTIVE);
496
497    int testNum = MEMP_NUM_NETCONN;
498    dbg("testNum %d\r\n", testNum);
499    ChipseaWifiMsg msg = {
500        .eventId = WIFI_START_SCAN,
501        .payLoad = 0,
502    };
503
504    if (WifiCreateLock() != WIFI_SUCCESS) {
505        return ERROR_WIFI_NOT_AVAILABLE;
506    }
507    if (rtos_queue_write(g_wifiData.wifiQueue, &msg, 1, false) != 0) {
508        dbg("wifiDevice:rtos_queue_write err\r\n");
509        WifiUnlock();
510        return ERROR_WIFI_NOT_AVAILABLE;
511    }
512    WifiUnlock();
513    return WIFI_SUCCESS;
514}
515
516……
517int GetSignalLevel(int rssi, int band)
518{
519    if (band == HOTSPOT_BAND_TYPE_2G) {
520        if (rssi >= RSSI_LEVEL_4_2_G)
521            return RSSI_LEVEL_4;
522        if (rssi >= RSSI_LEVEL_3_2_G)
523            return RSSI_LEVEL_3;
524        if (rssi >= RSSI_LEVEL_2_2_G)
525            return RSSI_LEVEL_2;
526        if (rssi >= RSSI_LEVEL_1_2_G)
527            return RSSI_LEVEL_1;
528    }
529
530    if (band == HOTSPOT_BAND_TYPE_5G) {
531        if (rssi >= RSSI_LEVEL_4_5_G)
532            return RSSI_LEVEL_4;
533        if (rssi >= RSSI_LEVEL_3_5_G)
534            return RSSI_LEVEL_3;
535        if (rssi >= RSSI_LEVEL_2_5_G)
536            return RSSI_LEVEL_2;
537        if (rssi >= RSSI_LEVEL_1_5_G)
538            return RSSI_LEVEL_1;
539    }
540    return ERROR_WIFI_INVALID_ARGS;
541}
542
543```
544
545### kernel子系统
546
547kernel子系统,我们需要配置跟wifi密切相关的lwip组件,使用社区的"lwip"三方件,同时指定用于适配三方lwip和wifi系统的目录。
548
549`LiteOS-M kernel`目录下默认配置了`lwip`,因而具有编译功能,可以在`kernel`组件中指定`lwip`编译的目录。如下:
550
551```
552    {
553      "subsystem": "kernel",
554      "components": [
555        {
556          "component": "liteos_m",
557          "features": [
558             "ohos_kernel_liteos_m_lwip_path = \"//device/soc/chipsea/cst85/liteos_m/sdk/modules/lwip-2.1\""
559		 --- 指定在芯片厂商目录中进行适配
560          ]
561        }
562      ]
563    },
564```
565
566在`//device/soc/chipsea/cst85/liteos_m/sdk/modules/lwip-2.1/BUILD.gn`文件中,描述了`lwip`的编译,如下:
567
568```
569import("//kernel/liteos_m/liteos.gni")
570import("$LITEOSTHIRDPARTY/lwip/lwip.gni")
571import("$LITEOSTOPDIR/components/net/lwip-2.1/lwip_porting.gni")
572
573module_switch = defined(LOSCFG_NET_LWIP_SACK)
574module_name = "lwip"
575kernel_module(module_name) {
576  sources = LWIP_PORTING_FILES + LWIPNOAPPSFILES -
577            [ "$LWIPDIR/api/sockets.c" ] + [ "porting/src/ethernetif.c" ]		 --- 增加ethernetif.c文件,用以适配ethernet网卡的初始化适配
578  defines = [ "LITEOS_LWIP=1" ]
579  defines += [ "CHECKSUM_BY_HARDWARE=1" ]
580}
581
582config("public") {
583  defines = [ "_BSD_SOURCE=1" ]
584  include_dirs =
585      [ "porting/include" ] + LWIP_PORTING_INCLUDE_DIRS + LWIP_INCLUDE_DIRS
586}
587
588```
589
590在`//device/soc/chipsea/cst85/liteos_m/sdk/modules/lwip-2.1/porting/include/lwip/lwipopts.h`文件中,说明原有`lwip`配置选项保持不变,软总线会依赖这些配置选项,并且新增硬件适配的配置项,如下:
591
592```
593#ifndef _PORTING_LWIPOPTS_H_
594#define _PORTING_LWIPOPTS_H_
595
596#include_next "lwip/lwipopts.h"				 --- 保持原来的配置项不变
597
598#define LWIP_NETIF_STATUS_CALLBACK      1
599#define LWIP_CHECKSUM_ON_COPY           0
600#define CHECKSUM_GEN_UDP                0	 --- 新增硬件适配选项
601
602#endif /* _PORTING_LWIPOPTS_H_ */
603
604```
605
606在`//device/soc/chipsea/cst85/liteos_m/sdk/modules/lwip-2.1/porting/net_al.c`文件中,说明对`ethernet`网卡初始化的适配,如下:
607
608```
609static err_t net_if_init(struct netif *net_if)
610{
611    err_t status = ERR_OK;
612    struct fhost_vif_tag *vif = (struct fhost_vif_tag *)net_if->state;
613
614    #if LWIP_NETIF_HOSTNAME
615    {
616        /* Initialize interface hostname */
617        net_if->hostname = "CsWlan";
618    }
619    #endif /* LWIP_NETIF_HOSTNAME */
620
621    net_if->name[ 0 ] = 'w';
622    net_if->name[ 1 ] = 'l';
623
624    net_if->output = etharp_output;
625    net_if->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_IGMP;
626    net_if->hwaddr_len = ETHARP_HWADDR_LEN;
627    net_if->mtu = LLC_ETHER_MTU;
628    net_if->linkoutput = net_if_output;
629    memcpy(net_if->hwaddr, &vif->mac_addr, ETHARP_HWADDR_LEN);
630
631    return status;
632}
633
634```
635
636### startup子系统
637
638为了运行XTS或者APP_FEATURE_INIT等应用框架,我们适配了startup子系统的bootstrap_lite和syspara_lite组件。
639
640在`vendor/chipsea/wblink_demo/config.json`中新增对应的配置选项。
641
642```
643{
644  "subsystem": "startup",
645  "components": [
646	{
647	  "component": "bootstrap_lite"		 --- bootstrap_lite 部件
648	},
649	{
650	  "component": "syspara_lite",		 --- syspara_lite 部件
651	  "features": [
652		"enable_ohos_startup_syspara_lite_use_posix_file_api = true"
653	  ]
654	}
655  ]
656},
657```
658
659适配`bootstrap_lite`部件时,需要在连接脚本文件`//device/soc/chipsea/cst85/liteos_m/sdk/bsp/out/cst85f01/cst85f01.ld`中手动新增如下段:
660
661```
662       __zinitcall_bsp_start = .;
663      KEEP (*(.zinitcall.bsp0.init))
664      KEEP (*(.zinitcall.bsp1.init))
665      KEEP (*(.zinitcall.bsp2.init))
666      KEEP (*(.zinitcall.bsp3.init))
667      KEEP (*(.zinitcall.bsp4.init))
668      __zinitcall_bsp_end = .;
669      __zinitcall_device_start = .;
670      KEEP (*(.zinitcall.device0.init))
671      KEEP (*(.zinitcall.device1.init))
672      KEEP (*(.zinitcall.device2.init))
673      KEEP (*(.zinitcall.device3.init))
674      KEEP (*(.zinitcall.device4.init))
675      __zinitcall_device_end = .;
676      __zinitcall_core_start = .;
677      KEEP (*(.zinitcall.core0.init))
678      KEEP (*(.zinitcall.core1.init))
679      KEEP (*(.zinitcall.core2.init))
680      KEEP (*(.zinitcall.core3.init))
681      KEEP (*(.zinitcall.core4.init))
682      __zinitcall_core_end = .;
683      __zinitcall_sys_service_start = .;
684      KEEP (*(.zinitcall.sys.service0.init))
685      KEEP (*(.zinitcall.sys.service1.init))
686      KEEP (*(.zinitcall.sys.service2.init))
687      KEEP (*(.zinitcall.sys.service3.init))
688      KEEP (*(.zinitcall.sys.service4.init))
689      __zinitcall_sys_service_end = .;
690      __zinitcall_sys_feature_start = .;
691      KEEP (*(.zinitcall.sys.feature0.init))
692      KEEP (*(.zinitcall.sys.feature1.init))
693      KEEP (*(.zinitcall.sys.feature2.init))
694      KEEP (*(.zinitcall.sys.feature3.init))
695      KEEP (*(.zinitcall.sys.feature4.init))
696      __zinitcall_sys_feature_end = .;
697      __zinitcall_run_start = .;
698      KEEP (*(.zinitcall.run0.init))
699      KEEP (*(.zinitcall.run1.init))
700      KEEP (*(.zinitcall.run2.init))
701      KEEP (*(.zinitcall.run3.init))
702      KEEP (*(.zinitcall.run4.init))
703      __zinitcall_run_end = .;
704      __zinitcall_app_service_start = .;
705      KEEP (*(.zinitcall.app.service0.init))
706      KEEP (*(.zinitcall.app.service1.init))
707      KEEP (*(.zinitcall.app.service2.init))
708      KEEP (*(.zinitcall.app.service3.init))
709      KEEP (*(.zinitcall.app.service4.init))
710      __zinitcall_app_service_end = .;
711      __zinitcall_app_feature_start = .;
712      KEEP (*(.zinitcall.app.feature0.init))
713      KEEP (*(.zinitcall.app.feature1.init))
714      KEEP (*(.zinitcall.app.feature2.init))
715      KEEP (*(.zinitcall.app.feature3.init))
716      KEEP (*(.zinitcall.app.feature4.init))
717      __zinitcall_app_feature_end = .;
718      __zinitcall_test_start = .;
719      KEEP (*(.zinitcall.test0.init))
720      KEEP (*(.zinitcall.test1.init))
721      KEEP (*(.zinitcall.test2.init))
722      KEEP (*(.zinitcall.test3.init))
723      KEEP (*(.zinitcall.test4.init))
724      __zinitcall_test_end = .;
725      __zinitcall_exit_start = .;
726      KEEP (*(.zinitcall.exit0.init))
727      KEEP (*(.zinitcall.exit1.init))
728      KEEP (*(.zinitcall.exit2.init))
729      KEEP (*(.zinitcall.exit3.init))
730      KEEP (*(.zinitcall.exit4.init))
731      __zinitcall_exit_end = .;
732```
733
734需要新增上述段是因为`bootstrap_init`提供的对外接口,采用的是灌段的形式,最终会保存到上述链接段中(见`//utils/native/lite/include/ohos_init.h`文件)。
735
736bootstrap提供的自动初始化宏如下表所示:
737
738| 接口名                 | 描述                             |
739| ---------------------- | -------------------------------- |
740| SYS_SERVICE_INIT(func) | 标识核心系统服务的初始化启动入口。 |
741| SYS_FEATURE_INIT(func) | 标识核心系统功能的初始化启动入口。 |
742| APP_SERVICE_INIT(func) | 标识应用层服务的初始化启动入口。   |
743| APP_FEATURE_INIT(func) | 标识应用层功能的初始化启动入口。   |
744
745通过上面加载的组件编译出来的lib文件需要手动加入强制链接。
746
747​如在 `vendor/chipsea/wblink_demo/config.json` 中配置了`bootstrap_lite` 部件。
748
749```
750    {
751      "subsystem": "startup",
752      "components": [
753        {
754          "component": "bootstrap_lite"
755        },
756        ...
757      ]
758    },
759```
760
761​`bootstrap_lite`部件会编译`//base/startup/bootstrap_lite/services/source/bootstrap_service.c`,该文件中,通过`SYS_SERVICE_INIT`将`Init`函数符号灌段到`__zinitcall_sys_service_start`和`__zinitcall_sys_service_end`中。
762```
763static void Init(void)
764{
765    static Bootstrap bootstrap;
766    bootstrap.GetName = GetName;
767    bootstrap.Initialize = Initialize;
768    bootstrap.MessageHandle = MessageHandle;
769    bootstrap.GetTaskConfig = GetTaskConfig;
770    bootstrap.flag = FALSE;
771    SAMGR_GetInstance()->RegisterService((Service *)&bootstrap);
772}
773SYS_SERVICE_INIT(Init);   --- 通过SYS启动即SYS_INIT启动就需要强制链接生成的lib
774```
775
776在`//base/startup/bootstrap_lite/services/source/BUILD.gn`文件中,把文件添加到编译sources中去:
777
778```
779static_library("bootstrap") {
780  sources = [
781    "bootstrap_service.c",
782    "system_init.c",
783  ]
784  ....
785```
786
787由于`Init`函数是没有显式调用它,所以需要将它强制链接到最终的镜像。在这里,我们通过在 `device/board/chipsea/cst85_wblink/config.gni` 中如下配置ld_flags:
788
789```
790   board_ld_flags += [
791    "-Wl,--whole-archive",
792    "-lexample",
793    "-lhiview_lite",
794    "-lhilog_lite",
795    "-lhievent_lite",
796    "-lbroadcast",
797    "-lbootstrap",
798    "-Wl,--no-whole-archive",
799  ]
800
801```
802
803### utils子系统
804
805进行`utils`子系统适配需要添加`kv_store`/`js_builtin`/`timer_task`/`kal_timer`部件,直接在`config.json`配置即可。
806
807```
808{
809  "subsystem": "utils",
810  "components": [
811	{
812	  "component": "kv_store",
813	  "features": [
814		"enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true"
815	  ]
816	},
817
818  ]
819},
820```
821
822与适配`syspara_lite`部件类似,适配`kv_store`部件时,键值对会写到文件中。在轻量系统中,文件操作相关接口有`POSIX`接口与`HalFiles`接口这两套实现。因为对接内核的文件系统,采用`POSIX`相关的接口,所以`features`需要增加`enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true`。如果对接`HalFiles`相关的接口实现的,则无须修改。
823
824
825### xts子系统
826
827xts子系统的适配,以`//vendor/chipsea/xts_demo/config.json`为例,需要加入组件选项:
828
829```
830"subsystem": "xts",
831"components": [
832  { "component": "xts_acts", "features":
833    [
834	  "config_ohos_xts_acts_utils_lite_kv_store_data_path = \"/data\"",
835      "enable_ohos_test_xts_acts_use_thirdparty_lwip = true"
836    ]
837  },
838  { "component": "xts_tools", "features":[] }
839]
840```
841其中需要在`device/board/chipsea/cst85_wblink/liteos_m/config.gni`强制链接xts lib,
842
843```
844 board_ld_flags += [
845    "-Wl,--whole-archive",
846     "-lhctest",
847     "-lmodule_ActsParameterTest",
848     "-lmodule_ActsBootstrapTest",
849     "-lmodule_ActsDfxFuncTest",
850     "-lmodule_ActsKvStoreTest",
851     "-lmodule_ActsSamgrTest",
852     "-lmodule_ActsWifiServiceTest",
853     "-lmodule_ActsDsoftbusMgrTest",
854 ]
855```
856