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