OpenHarmony实战:Combo解决方案之ASR芯片移植案例

本方案基于 OpenHarmony LiteOS-M 内核,使用 ASR582X 芯片的 DEV.WIFI.A 开发板进行开发移植。作为典型的 IOT Combo(Wi-Fi+BLE)解决方案,本文章介绍 ASR582X 的适配过程。

编译移植

目录规划

本方案的目录结构使用 Board 和 Soc 解耦的思路:

device
├── board                                --- 单板厂商目录
│   └── lango                            --- 单板厂商名字:朗国
│       └── dev_wifi_a                   --- 单板名:DEV.WIFI.A
└── soc                                  --- SoC厂商目录└── asrmicro                         --- SoC厂商名字:翱捷科技└── asr582x                      --- SoC Series名:ASR582X系列芯片

产品样例目录规划为:

vendor
└── asrmicro                             --- 开发产品样例厂商目录,翱捷科技的产品样例├── wifi_demo                        --- 产品名字:Wi-Fi样例代码└── xts_demo                         --- 产品名字: XTS测试样例

产品定义

以 vendor/asrmicro/wifi_demo 为例,这里描述了产品使用的内核、单板、子系统等信息。其中,内核、单板型号、单板厂商需要提前规划好,也是预编译指令(hb set)所关注的。这里填入的信息与规划的目录相对应。例如:

{"product_name": "wifi_demo",          --- 产品名"type": "mini",                       --- 系统类型: mini"version": "3.0",                     --- 系统版本: 3.0"device_company": "lango",            --- 单板厂商:lango"board": "dev_wifi_a",                --- 单板名:dev_wifi_a"kernel_type": "liteos_m",            --- 内核类型:liteos_m"kernel_version": "3.0.0",            --- 内核版本:3.0.0"subsystems": []                      --- 子系统
}

这里的 device_company 和 board 用于关联出//device/board/<device_company>/目录。

单板配置

在关联到的目录下,以 device/board/lango/dev_wifi_a 为例,需要在 liteos_m 目录下放置 config.gni 文件,这个配置文件用于描述该单板的信息,包括 CPU、toolchain、kernel、compile flags 等。例如:

# 内核类型
kernel_type = "liteos_m"
# 内核版本
kernel_version = "3.0.0"
# 单板CPU类型
board_cpu = "cortex-m4"
# 工具链,这里使用arm-none-eabi
board_toolchain = "arm-none-eabi"
# 工具链路径,可以使用系统路径,填"",也可以自定义,如下:
board_toolchain_path = rebase_path("//device/soc/asrmicro/gcc/gcc-arm-none-eabi/Linux64/bin")
# 单板相关的编译参数
board_cflags = []
# 单板相关的链接参数
board_ld_flags = []
# 单板相关的头文件
board_include_dirs = []

预编译

在正确配置好产品的目录、产品定义、单板配置后,在工程根目录下输入预编译指令 hb set,在显示的列表中就可以找到相关的产品。

选择好产品后,输入回车就会在根目录下自动生成 ohos_config.json 文件,这里会将要编译的产品信息列出。

内核移植

Kconfig 适配

在//kernel/liteos_m 的编译中,需要在相应的单板以及 SoC 目录下使用 Kconfig 文件进行索引。
单板目录的 Kconfig,以 //device/board/lango 为例:

├── dev_wifi_a                                   --- dev_wifi_a单板配置目录
│   ├── Kconfig.liteos_m.board                   --- 单板的配置选项
│   ├── Kconfig.liteos_m.defconfig.board         --- 单板的默认配置项
│   └── liteos_m
│       └── config.gni                           --- 单板的配置文件
├── Kconfig.liteos_m.boards                      --- 单板厂商下Boards配置信息
└── Kconfig.liteos_m.defconfig.boards            --- 单板厂商下Boards默认配置信息

在 dev_wifi_a/Kconfig.liteos_m.board 中,配置只有 SOC_ASR5822S 被选后,BOARD_DEV_WIFI_A 才可被选:

config BOARD_DEV_WIFI_Abool "select board DEV_WIFI_A"depends on SOC_ASR5822S

SoC 目录的 Kconfig,以 //device/soc/asrmicro 为例:

├── asr582x                                      --- ASR582X系列
│   ├── Kconfig.liteos_m.defconfig.asr5822s      --- ASR5822S芯片默认配置
│   ├── Kconfig.liteos_m.defconfig.series        --- ASR582X系列默认配置
│   ├── Kconfig.liteos_m.series                  --- ASR582X系列配置
│   └── Kconfig.liteos_m.soc                     --- ASR582X芯片配置
├── Kconfig.liteos_m.defconfig                   --- SoC默认配置
├── Kconfig.liteos_m.series                      --- Series配置
└── Kconfig.liteos_m.soc                         --- SoC配置

在 asr582x/Kconfig.liteos_m.series 中:

config SOC_SERIES_ASR582Xbool "ASR582X Series"select ARMselect SOC_COMPANY_ASRMICRO              --- 选择 SOC_COMPANY_ASRMICROselect CPU_CORTEX_M4helpEnable support for ASR582X series

只有选择了 SOC_SERIES_ASR582X,在 asr582x/Kconfig.liteos_m.soc 中才可以选择 SOC_ASR5822S:

choiceprompt "ASR582X series SoC"depends on SOC_SERIES_ASR582X
config SOC_ASR5822S                         --- 选择 SOC_ASR5822Sbool "SoC ASR5822S"
endchoice

综上所述,要编译单板 BOARD_DEV_WIFI_A,则要分别选中:SOC_COMPANY_ASRMICRO、SOC_SERIES_ASR582X、SOC_ASR5822S,可以在 kernel/liteos_m 中执行 make menuconfig 进行选择配置

配置后的文件会默认保存在 //vendor/asrmicro/wifi_demo/kernel_configs/debug.config,也可以直接填写 debug.config:

LOSCFG_BOARD_DEV_WIFI_A=y
LOSCFG_SOC_COMPANY_ASRMICRO=y
LOSCFG_SOC_SERIES_ASR582X=y
LOSCFG_SOC_ASR5822S=y

模块化编译

Board 和 SoC 的编译采用模块化的编译方法,从 kernel/liteos_m/BUILD.gn 开始逐级向下递增。本方案的适配过程如下:

  1. 在 //device/board/lango 中新建文件 BUILD.gn,新增内容如下:

    if (ohos_kernel_type == "liteos_m") {import("//kernel/liteos_m/liteos.gni")module_name = get_path_info(rebase_path("."), "name")module_group(module_name) {modules = ["dev_wifi_a",                     # 单板模块"hcs",                            # hcs文件的对应模块]}
    }
    

    在上述 BUILD.gn 中,dev_wifi_a 以及 hcs 即是按目录层级组织的模块名。

  2. 在 //device/soc/asrmicro 中,使用同样的方法,新建文件 BUILD.gn,按目录层级组织,新增内容如下:

    if (ohos_kernel_type == "liteos_m") {import("//kernel/liteos_m/liteos.gni")module_name = get_path_info(rebase_path("."), "name")module_group(module_name) {modules = ["asr582x",]}
    }
    
  3. 在 //device/soc/asrmicro 各个层级模块下,同样新增文件 BUILD.gn,将该层级模块加入编译,以 //device/soc/asrmicro/asr582x/liteos_m/sdk/startup/BUILD.gn 为例:

    import("//kernel/liteos_m/liteos.gni")
    config("public") {include_dirs = [ "." ]                 # 公共头文件
    }
    kernel_module("asr_startup") {           # 编译的模块sources = [                            # 编译的源文件"startup.c","board.c","startup_cm4.S",]include_dirs = [                       # 模块内使用到的头文件"...",]
    }
    
  4. 为了组织链接以及一些编译选项,在 //device/soc/asrmicro/asr582x/liteos_m/sdk/config/BUILD.gn 下的 config("public")填入了相应的参数:

    config("public") {include_dirs = []                       # 公共头文件ldflags = []                            # 链接参数,包括ld文件libs = []                               # 链接库defines = []                            # 定义

    说明:
    建议公共的参数选项以及头文件不在各个组件中重复填写。

  5. 为了组织一些产品侧的应用,本方案在 vendor 相应的 config.json 加入了相应的 list 来组织,以 //vendor/asrmicro/wifi_demo/config.json 为例,在 config.json 增加对应的 list:

    "tests_list": [                       --- demo list{"enable": "true",                 --- list开关"test_modules": ["example",                      --- OS基础demo"wifi_test"                     --- Wi-Fi demo]}
    ]
    

    这里将 demo 作为了模块来管理,开启/关闭某个 demo,在 tests_list 中增减项即可。tests_list 在 gn 中可以直接被读取,需要在 //device/board/lango/dev_wifi_a/liteos_m/config.gni 加入以下内容:

    product_conf = read_file("${product_path}/config.json", "json")
    product_name = product_conf.product_name
    tests_list = product_conf.tests_list
    

    读取 list 后即可在相应的链接选项上加入相关的组件库,需要在 //device/soc/asrmicro/asr582x/liteos_m/sdk/config/BUILD.gn 加入以下内容:

    foreach(test_item, tests_list) {test_enable = test_item.enableif(test_enable == "true"){foreach(test_module, test_item.test_modules) {ldflags += [ "-l${test_module}" ]}}
    }
    

C 库适配

为了整个系统不区分用户态内核态,上层组件与内核共用一套基于 musl 的 C 库,本方案使用 musl C,三方库见 //third_party/musl/porting/liteos_m/kernel/BUILD.gn
kernel 另外对 malloc 相应的 code 进行了改造适配,适配文件见 //kernel/liteos_m/kal/libc/musl/porting/src/malloc.c
在本方案中,printf 相关的接口使用开源代码实现,适配文件见 //device/soc/asrmicro/asr582x/liteos_m/sdk/drivers/platform/system/printf-stdarg.c
为了满足 printf 相关接口的链接调用,需要在 //device/board/lango/dev_wifi_a/liteos_m/config.gni 的新增这些函数的 wrap 链接:

board_ld_flags += ["-Wl,--wrap=printf","-Wl,--wrap=sprintf","-Wl,--wrap=snprintf","-Wl,--wrap=vprintf","-Wl,--wrap=vsprintf","-Wl,--wrap=vsnprintf",
]

shell 适配

为了方便调试,本方案集成了内核的 shell 组件,可以在 make menuconfig 中的 Debug 中选中 Enable Shell,或者在 //vendor/asrmicro/wifi_demo/kernel_configs/debug.config 文件中填入 LOSCFG_SHELL=y
shell 组件需要进行初始化,可参考 device/soc/asrmicro/asr582x/liteos_m/sdk/startup/board.c

ret = LosShellInit();
if (ret != LOS_OK) {printf("LosShellInit failed! ERROR: 0x%x\n", ret);
}
ret = OsShellInit();
if (ret != LOS_OK) {printf("OsShellInit failed! ERROR: 0x%x\n", ret);
}

在初始化之后,每个 shell 命令需要进行注册,例如:vendor/asrmicro/wifi_demo/tests/wifi/wifi_app.c

osCmdReg(CMD_TYPE_STD, "wifi_open", 0, (CMD_CBK_FUNC)ap_conn_func);    // 连接AP的指令,这里可以带参
osCmdReg(CMD_TYPE_EX, "wifi_close", 0, (CMD_CBK_FUNC)ap_close_func);   // 断开指令

内核启动适配

单板进入到 main 函数后,首先会进行单板初始化,然后需要注册中断,之后再进行内核的初始化和调度。
注册中断,可参考 //device/soc/asrmicro/asr582x/liteos_m/sdk/startup/board.c:

ArchHwiCreate(UART1_IRQn,configLIBRARY_NORMAL_INTERRUPT_PRIORITY,0,UART1_IRQHandler,0);   // UART中断
ArchHwiCreate(GPIO_IRQn,configLIBRARY_NORMAL_INTERRUPT_PRIORITY,0,GPIO_IRQHandler,0);     // GPIO中断

内核初始化示例如下:

osStatus_t ret = osKernelInitialize();                                                    // 内核初始化
if(ret == osOK)
{threadId = osThreadNew((osThreadFunc_t)sys_init,NULL,&g_main_task);                   // 创建init线程if(threadId!=NULL){osKernelStart();                                                                  // 线程调度}
}

在 sys_init 中,需要对 OpenHarmony 的系统组件进行初始化:

...
DeviceManagerStart();           // HDF初始化
OHOS_SystemInit();              // OpenHarmony系统组件初始化
....

HDF 驱动框架适配

HDF 驱动框架提供了一套应用访问硬件的统一接口,可以简化应用开发,添加 HDF 组件需要在 //vendor/asrmicro/wifi_demo/kernel_configs/debug.config 添加:

LOSCFG_DRIVERS_HDF=y
LOSCFG_DRIVERS_HDF_PLATFORM=y

同时需在 board 中新增对应开发板硬件配置描述文件,位于 //device/board/lango/hcs。本案例以 GPIO 以及 UART 为例,移植过程如下:

GPIO 适配
  1. 芯片驱动适配文件位于 //drivers/hdf_core/adapter/platform 目录,在 gpio 目录增加 gpio_asr.c 文件,在 BUILD.gn 中增加新增的驱动文件编译条件:
    if (defined(LOSCFG_SOC_COMPANY_ASRMICRO)) {sources += [ "gpio_asr.c" ]
    }
    
  2. gpio_asr.c 中驱动描述文件如下:
    struct HdfDriverEntry g_GpioDriverEntry = {.moduleVersion = 1,.moduleName = "ASR_GPIO_MODULE_HDF",.Init = GpioDriverInit,.Release = GpioDriverRelease,
    };
    HDF_INIT(g_GpioDriverEntry);
    
  3. 在 //device/board/lango/hcs 添加 gpio 硬件描述信息文件 gpio.hcs, 映射后的 gpio0 控制板卡上的可编程 LED,gpio1 对应用户按键,hcs 内容如下:
    root {platform {gpio_config {match_attr = "gpio_config";pin = [0, 1];// led3: GPIO9// user key: GPIO7realPin = [9, 7];config = [5, 1];pinNum = 2;}}
    }
    
  4. gpio.hcs 的配置信息会在 GpioDriverInit 进行加载,并执行对应 GPIO 引脚的初始化。应用层控制 LED 灯和读取按键信息只需要以下简单的代码:
    int32_t GpioKeyIrqFunc(uint16_t gpio, void *data)
    {printf("user key %d pressed\n", gpio);
    }
    GpioSetIrq(1, OSAL_IRQF_TRIGGER_FALLING, GpioKeyIrqFunc, NULL);
    GpioWrite(0, 0);
    lega_rtos_delay_milliseconds(1000);
    GpioWrite(0, 1);
    
UART 适配
  1. 芯片驱动适配文件位于 //drivers/adapter/platform 目录,在 uart 目录增加 uart_asr.c 和 uart_asr.h 文件,在 BUILD.gn 中增加新增的驱动文件编译条件:
    if (defined(LOSCFG_SOC_COMPANY_ASRMICRO)) {sources += [ "uart_asr.c" ]
    }
    
  2. uart_asr.c 中驱动描述文件如下:
    struct HdfDriverEntry g_hdfUartDevice = {.moduleVersion = 1,.moduleName = "HDF_PLATFORM_UART",.Bind = HdfUartDeviceBind,.Init = HdfUartDeviceInit,.Release = HdfUartDeviceRelease,
    };
    HDF_INIT(g_hdfUartDevice);
    
  3. 在 //device/board/lango/hcs 添加 gpio 硬件描述信息文件 uart.hcs, hcs 内容如下:
    controller_uart0 :: uart_controller {match_attr = "asr582x_uart_0";port = 0;                        /* UART_ID_0 */pin_tx_pin = 0;                  /* IO_PIN_10 */pin_tx_mux = 25;                 /* IO_MUX_2  */pin_rx_pin = 1;                  /* IO_PIN_11 */pin_rx_mux = 25;                 /* IO_MUX_2 */tx_rx = 3;                       /* TX_RX MODE */
    }
    
  4. gpio.hcs 的配置信息会在 HdfUartDeviceInit 进行加载,并执行对应串口引脚的初始化。应用层测试串口代码如下:
    DevHandle uart_handle = UartOpen(0);
    UartSetBaud(uart_handle, 115200);
    ...
    attr.dataBits = UART_ATTR_DATABIT_8;
    attr.parity = UART_ATTR_PARITY_NONE;
    attr.stopBits = UART_ATTR_STOPBIT_1;
    ret = UartSetAttribute(uart_handle, &attr);
    ret = UartWrite(uart_handle, send_data, strlen(send_data));
    ret = UartRead(uart_handle, recv_data, sizeof(recv_data) - 1);
    ...
    

OpenHarmony 组件移植

子系统的编译选项入口在相应产品 config.json 下,以下以 //vendor/asrmicro/wifi_demo/config.json 为例。

lwIP 组件

lwIP 组件的源码在 //third_party/lwip,OpenHarmony 在 kernel 中做了定制化,//kernel/liteos_m/components/net/lwip-2.1,包括一些接口的重定义,结构体的重定义等。
lwIP 组件适配:
lwIP 是一个小型开源的 TCP/IP 协议栈,LiteOS-M 已对开源 lwIP 做了适配和功能增强,lwIP 代码分为两部分:

  • third_party/lwip 目录下是 lwIP 开源代码,里面只做了少量的侵入式修改,为了适配增强功能。
  • kernel/liteos_m/components/net/lwip-2.1 目录下是 lwIP 适配和功能增强代码,里面提供了 lwIP 的默认配置文件。
    如果需要使用 lwIP 组件,请按如下步骤适配:
  1. 在产品目录下新建一个目录用来存放产品的适配文件,如 lwip_adapter。
  2. 在 lwip_adapter 目录下新建一个目录 include,用来存放适配的头文件。
  3. 在 include 目录下新建目录 lwip,并在 lwip 目录下新建头文件 lwipopts.h,代码如下所示,如果默认配置不能满足产品使用,可自行根据产品使用情况修改配置,如关闭 DHCP 功能。
    #ifndef _LWIP_ADAPTER_LWIPOPTS_H_
    #define _LWIP_ADAPTER_LWIPOPTS_H_
    #include_next "lwip/lwipopts.h"
    #undef LWIP_DHCP#define LWIP_DHCP                       0 // 关闭DHCP功能
    #endif /* _LWIP_ADAPTER_LWIPOPTS_H_ */
    
  4. 将 kernel/liteos_m/components/net/lwip-2.1 目录下的 BUILD.gn 复制到 lwip_adapter 目录下,并按如下修改。
    import("//kernel/liteos_m/liteos.gni")
    import("$LITEOSTHIRDPARTY/lwip/lwip.gni")
    import("$LITEOSTOPDIR/components/net/lwip-2.1/lwip_porting.gni")
    module_switch = defined(LOSCFG_NET_LWIP_SACK)
    module_name = "lwip"kernel_module(module_name) {sources = LWIP_PORTING_FILES + LWIPNOAPPSFILES - [ "$LWIPDIR/api/sockets.c" ]include_dirs = [ "//utils/native/lite/include" ]
    }
    #添加新增加的适配头文件路径include
    config("public") {include_dirs = [ "include" ] + LWIP_PORTING_INCLUDE_DIRS + LWIP_INCLUDE_DIRS
    }
    
  5. 在产品的配置文件(如 config.json)中设置 lwIP 的编译路径,即步骤 4 中 BUILD.gn 的路径。
    {"subsystem": "kernel","components": [{ "component": "liteos_m", "features":["ohos_kernel_liteos_m_lwip_path = \"//xxx/lwip_adapter\"" ] }]
    },
    
  6. 在产品的内核编译配置文件中,如 kernel_config/debug.config,打开编译 lwIP 的开关。
    LOSCFG_NET_LWIP=y
    

本案例在 config.json 中设置 lwIP 的路径如下:

"subsystem": "kernel",
"components": [{"component": "liteos_m","features": ["ohos_kernel_liteos_m_lwip_path = \"//device/soc/asrmicro/asr582x/liteos_m/components/net/lwip-2.1\""]}
]

另外,需在内核编译配置文件 kernel_config/debug.config 中,打开编译 lwIP 的开关,如下:

LOSCFG_NET_LWIP=y

security 组件

security 需要在 config.json 中打开相应的选项,本案例移植了三方库中的 mbedtls(//third_party/mbedtls)作为加密模块,选项配置如下:

"subsystem": "security",
"components": [{ "component": "huks", "features":[..."ohos_security_huks_mbedtls_porting_path = \"//device/soc/asrmicro/asr582x/liteos_m/components/mbedtls\""]}
]

在上述目录中,需要对 mbedtls 做配置,可见 config/config_liteos_m.h。需要注意的是,如果使用 mbedtls 的 RNG 的能力(比如 dsoftbus 组件在 //foundation/communication/dsoftbus/adapter/common/mbedtls/softbus_adapter_crypto.c 中有使用),要指定产生随机数的熵源。本案例使用了 ASR582X 的硬件随机数能力,需要打开如下宏定义:

#define MBEDTLS_ENTROPY_HARDWARE_ALT

打开此宏后,需要实现 entropy_hardware_alt 接口,可见 library/entropy_hardware_alt.c

wifi_lite 组件

wifi_lite 组件的选项配置如下:

"subsystem": "communication",
"components": [{ "component": "wifi_lite", "features":[] }]

与 Wi-Fi 有关的实现在 //device/soc/asrmicro/asr582x/liteos_m/sdk/hal/src/wifi_adapter.c 下。
本案例也提供了使用 wifi_lite 相关接口的 Demo,可见 //vendor/asrmicro/wifi_demo/tests/wifi/wifi_app.c,这里提供了两个连接的测试指令:
表 1 ASR Wi-Fi 连接指令

指令参数说明
wifi_opensta [SSID] [KEY]连接路由指令,例如:wifi_open sta ASR_AP test123456
wifi_close断开连接指令

xts 组件

xts 组件的适配,以 //vendor/asrmicro/xts_demo/config.json 为例,需要加入组件选项:

"subsystem": "xts",
"components": [{ "component": "xts_acts", "features":["enable_ohos_test_xts_acts_use_thirdparty_lwip = true"]},{ "component": "xts_tools", "features":[] }
]

另外,xts 功能也使用了 list 来组织,可参考[模块化编译],在 config.json 文件中增减相应模块:

"xts_list": [{"enable": "true","xts_modules": ["ActsKvStoreTest","ActsDfxFuncTest","ActsHieventLiteTest","ActsSamgrTest","ActsParameterTest","ActsWifiServiceTest","ActsWifiIotTest","ActsBootstrapTest"]}
],

dsoftbus 组件

dsoftbus 组件提供了设备间的发现连接、组网和传输能力,本方案以 Wi-Fi 设备间的软总线能力为例。
依赖组件:lwIP 组件、security 组件、wifi_lite 组件。
前置条件:设备需先连接路由,所有的组网设备需在同一局域网中。
dsoftbus 组件的选项配置如下:

"subsystem": "communication",
"components": [{ "component": "dsoftbus", "features":[] }]

在 //vendor/asrmicro/wifi_demo 下提供了 dsoftbus 的测试 Demo,打开该功能需修改 //vendor/asrmicro/wifi_demo/tests/BUILD.gn

declare_args() {asr_dsoftbus_test = true              # 打开dsoftbus demo编译
}

另外,需在 //vendor/asrmicro/wifi_demo/config.json 中添加 dsoftbus_test 模块:

"tests_list": [{"enable": "true","test_modules": ["wifi_test","dsoftbus_test"                 # 打开dsoftbus_test模块]}
]

dsoftbus 组件的启动接口可参考 //vendor/asrmicro/wifi_demo/tests/dsoftbus/dsoftbus_app.c

InitSoftBusServer();

dsoftbus 组件的运行需至少预留 80KB RAM。如资源不够,可对其它地方进行剪裁。例如,可在以下文件修改 lwIP 组件:
//kernel_liteos_m/blob/master/components/net/lwip-2.1/porting/include/lwip/lwipopts.h

#define TCPIP_THREAD_STACKSIZE          0x2000              // 缩小TCPIP任务栈大小

在 communication_dsoftbus 仓中,加入了-fPIC 编译选项,这样会让编译器产生与位置无关代码,并使用相对地址,但是在 LiteOS-M 核中使用的是静态库,不推荐使用。
建议开发者手动注释-fPIC 编译选项,后续会推进 OpenHarmony 统一规划此编译选项的开关。修改方法是在如下的四个文件中,找到"-fPIC"选项,并全部注释:
//foundation/communication/dsoftbus/core/common/BUILD.gn
//foundation/communication/dsoftbus/core/frame/BUILD.gn
//foundation/communication/dsoftbus/sdk/BUILD.gn
//foundation/communication/dsoftbus/components/nstackx_mini/nstackx_ctrl/BUILD.gn
软总线的组网需要通过设备认证,在研发阶段,可以把认证跳过,先行调试组网以及传输能力,需将文件 //foundation/communication/dsoftbus/core/authentication/src/auth_manager.c 中的 HandleReceiveDeviceId 函数替换为如下实现:

void HandleReceiveDeviceId(AuthManager *auth, uint8_t *data)
{uint8_t tempKey[SESSION_KEY_LENGTH] = {0};if (auth == NULL || data == NULL) {SoftBusLog(SOFTBUS_LOG_AUTH, SOFTBUS_LOG_ERROR, "invalid parameter");return;}if (AuthUnpackDeviceInfo(auth, data) != SOFTBUS_OK) {SoftBusLog(SOFTBUS_LOG_AUTH, SOFTBUS_LOG_ERROR, "AuthUnpackDeviceInfo failed");AuthHandleFail(auth, SOFTBUS_AUTH_UNPACK_DEVID_FAILED);return;}if (auth->side == SERVER_SIDE_FLAG) {if (EventInLooper(auth->authId) != SOFTBUS_OK) {SoftBusLog(SOFTBUS_LOG_AUTH, SOFTBUS_LOG_ERROR, "auth EventInLooper failed");AuthHandleFail(auth, SOFTBUS_MALLOC_ERR);return;}if (AuthSyncDeviceUuid(auth) != SOFTBUS_OK) {AuthHandleFail(auth, SOFTBUS_AUTH_SYNC_DEVID_FAILED);}(void)memset_s(tempKey, SESSION_KEY_LENGTH, 1, SESSION_KEY_LENGTH);AuthOnSessionKeyReturned(auth->authId, tempKey, SESSION_KEY_LENGTH); return;}//VerifyDeviceDevLvl(auth);                                            --- 这里注释认证过程(void)memset_s(tempKey, SESSION_KEY_LENGTH, 1, SESSION_KEY_LENGTH);AuthOnSessionKeyReturned(auth->authId, tempKey, SESSION_KEY_LENGTH);
}

在正确配置并编译烧录后,设备使用 wifi_open 指令连接路由,连接成功后,设备会自动进行组网。如下为组网成功截图:

其它组件的适配过程与官方以及其它厂商的过程类似,不再赘述。

todo

  • 待支持 BLE
  • 待丰富 Wi-Fi 测试指令

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(HarmonyOS NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/295128.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mac上怎么合并多张图片?

Mac上怎么合并多张图片&#xff1f;上班过的小伙伴都应该知道&#xff0c;合并拼接图片是一件非常重要且经常需要使用到的图片处理技术&#xff0c;将多张图片合并拼成一张之后能够展现出更多的图片内容。在Mac电脑上&#xff0c;合并多张图片是一项常见的任务&#xff0c;无论…

大话设计模式之抽象工厂模式

抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种方式来创建一系列相关或依赖对象的家族&#xff0c;而无需指定其具体类。该模式通过提供一个抽象工厂接口&#xff0c;定义了一组可以创建不同类型对象的方法&#…

JavaScript_与html结合方式

JavaScript_语法 ECMAScript&#xff1a;客户端脚本语言的标准 1.基本语法 1.1 与html结合方式&#xff08;2种&#xff09; 1. 内部JS 定义<script>,标签体内容就是js代码 2. 外部JS 定义<script>,通过src属性引入外部的 js文件 注意&#xff1a; 1.<script>…

【opencv】教程代码 —videoio(2)将两个视频的每一帧逐一读取并计算其PSNR 和MSSIM...

本教程开始介绍的源代码将对每一帧执行PSNR测量&#xff0c;并且只对PSNR低于输入值的帧进行SSIM测量。为了可视化的目的&#xff0c;我们在OpenCV窗口中展示两幅图像&#xff0c;并将PSNR和MSSIM值打印到控制台。期望看到如下内容&#xff1a; video-input-psnr-ssim.cpp 将两…

【“状态机” 解析UART不定长度的协议帧】

【“状态机” 解析UART不定长度的协议帧】 1. 数据帧格式2. 状态机原理3. 代码实现 通信设计中考虑协议的灵活性&#xff0c;经常把协议设计成“不定长度”。如果一个系统接收上述“不定长度”的协议帧&#xff0c;将会有一个挑战–如何高效接收与解析。一个实例如下图&#xf…

Linux (Ubuntu)- mysql8 部署

1.基本部署 01》》先查看OS类型&#xff0c;如果是Ubuntu在往下边看 rootspray:/etc/mysql/mysql.conf.d# lsb_release -a LSB Version: core-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: …

Spring AOP + 自定义注解 实现公共字段的填充

Spring AOP 自定义注解 实现公共字段的填充 代码冗,不利于后期维护. 定义操作这些字段的方法类型 实现步骤&#xff1a; 自定义注解AutoFill,用于表示操作这些公共字段的方法自定义切面类AutoFillAspect,统一拦截&#xff0c;通过反射获取方法入参&#xff0c;并填充公共字段…

springboot之MybatisPlus

文章目录 一、ORM二、mybatis实际操作三、mybatis-plus 一、ORM 简单来说ORM就是一个能够帮我们把java中Bean类映射到数据库中。 使用mybatis-plus。 配置架包 <!-- MyBatisPlus依赖 --><dependency><groupId>com.baomidou</groupId><art…

多态--下

文章目录 概念多态如何实现的指向谁调谁&#xff1f;例子分析 含有虚函数类的大小是多少&#xff1f;虚函数地址虚表地址多继承的子类的大小怎么计算&#xff1f;练习题虚函数和虚继承 概念 优先使用组合、而不是继承; 继承会破坏父类的封装、因为子类也可以调用到父类的函数;…

MyBatis-Plus04(条件构造器)

条件构造器和常用接口 wrapper介绍 Wrapper &#xff1a; 条件构造抽象类&#xff0c;最顶端父类 AbstractWrapper &#xff1a; 用于查询条件封装&#xff0c;生成 sql 的 where 条件 QueryWrapper &#xff1a; 查询条件封装 UpdateWrapper &#xff1a; Update 条件封装 A…

源支付V7开源版2.99,修复各种提示错误

源支付V7开源版2.99&#xff0c;修复各种提示错误 加密说明&#xff1a;200拿来的&#xff0c;只有8.1这个文件加密&#xff0c;其他文件无任何加密&#xff0c;已修复各种提示错误 测试其他开源版安装提示错误&#xff0c;有几个文件是加密的 注&#xff1a;开发不易&#…

【更新】上市公司-ZF环保补贴、补助数据(2008-2022年)

01、数据简介 环保补贴&#xff0c;又称绿色补贴&#xff0c;是ZF在环保领域实施的一种特定补贴。它主要针对那些在经济主体意识上存在偏差或由于资金私有制而无法有效进行环保投资的企业。环保补贴的目的是解决环保问题&#xff0c;帮助企业改进环保设备和工艺&#xff0c;以…

职场新军—网络安全,这个行业的实际情况你知道吗?

作为IT行业的香饽饽&#xff0c;网络安全工程师可谓是金字塔尖上的摇钱树。这专业近几年的薪资一直狂飙&#xff0c;简直就是职业版的“月薪过万”&#xff01;但别急着入坑&#xff0c;毕竟不是每个学了网络安全的都能在金钱雨中舞蹈&#xff0c;有时候还得小心不被淘汰。 听…

基本电路理论入门讲解系列-电路和电路模型

&#x1f308;个人主页&#xff1a;会编程的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 电路 电路概念&#xff1a;把若干个电气设备和电气元件按照一定的方式组合起来&#xff0c;构成电流的通路&#xff0c;此路径的总体称为电路。在电子通信&#xff0c;自…

Oracle 中 where 和 on 的区别

1.Oracle 中 where 和 on 的区别 on&#xff1a;会先根据on后面的条件进行筛选&#xff0c;条件为真时返回该行&#xff0c;由于on的优先级高于left join&#xff0c;所以left join关键字会把左表中没有匹配的所有行也都返回&#xff0c;然后生成临时表返回,执行优先级高于…

遥感动态监测技术

很多人对动态监测和动态检测两个名词有疑惑。我们可以这样理解&#xff0c;动态监测是一个广义的名词&#xff0c;泛指数据预处理、变化信息发现与提取、变化信息挖掘与应用等&#xff0c;以对整个流程的叙述。动态检测是一个狭义的名词&#xff0c;主要指部分数据预处理、变化…

项目:USB键盘和鼠标的复合设备

我们的复合设备使用一个物理设备就可以完成多个功能。 使用复合设备同时完成USB键盘和鼠标功能&#xff0c;它的主要实现方式有两种&#xff0c; 第一个就是我们将多个设备描述符合并成一个&#xff0c;这个相对比较简单&#xff0c;我们只要根据相应的报告描述符处理数据就可…

vue3+vite 模板vue3-element-admin框架如何关闭当前页面跳转 tabs

使用模版: 有来开源组织 / vue3-element-admin 需要关闭的.vue 页面增加以下方法 //setup 里import {LocationQuery, useRoute, useRouter} from "vue-router"; const router useRouter(); function close() {console.log(|--router.currentRoute.value, router.cur…

C++入门:命名空间namespace,cin,cout,缺省参数,函数的重载

namespace本质上是定义了一个命名空间域 通过创建命名空间域可以预防变量的冲突问题 命名冲突时,编译器会首先从局部中找,然后从全局中找,但是不会从命名空间中找 eg. ::符号和命名空间 :: 是域作用限定符 就可以访问namespace bit中的rand了,否则就默认找局部或全局的ran…

2024年全新靠谱的FTP替代升级解决方案

随着企业规模的扩大和业务的多元化&#xff0c;传统的TCP协议在数据传输效率上逐渐显现出局限性。TCP协议虽然以其稳定性和可靠性被广泛应用&#xff0c;但在面对大规模数据传输时&#xff0c;其性能瓶颈逐渐成为企业发展的阻碍。同时&#xff0c;基于TCP的应用协议如Telnet、F…