当前位置: 首页 > news >正文

网站跳出率高的原因网站 内容 营销

网站跳出率高的原因,网站 内容 营销,wordpress 手机号注册,江苏嘉力电力建设有限公司网站往期知识点记录#xff1a; OpenHarmony#xff08;鸿蒙南向开发#xff09;——轻量系统STM32F407芯片移植案例 OpenHarmony#xff08;鸿蒙南向开发#xff09;——Combo解决方案之W800芯片移植案例 OpenHarmony#xff08;鸿蒙南向开发#xff09;——小型系统STM32M…往期知识点记录 OpenHarmony鸿蒙南向开发——轻量系统STM32F407芯片移植案例 OpenHarmony鸿蒙南向开发——Combo解决方案之W800芯片移植案例 OpenHarmony鸿蒙南向开发——小型系统STM32MP1芯片移植案例 OpenHarmony鸿蒙南向开发——标准系统方案之瑞芯微RK3568移植案例(上) OpenHarmony鸿蒙南向开发——标准系统方案之瑞芯微RK3568移植案例(下) 持续更新中…… TP TP驱动模型 主要包含Input模块HDIHardware Driver Interface接口定义及其实现对上层输入服务提供操作input设备的驱动能力接口HDI接口主要包括如下三大类 InputManager管理输入设备包括输入设备的打开、关闭、设备列表信息获取等InputReporter负责输入事件的上报包括注册、注销数据上报回调函数等InputController提供input设备的业务控制接口包括获取器件信息及设备类型、设置电源状态等。 图 1 INPUT模块HDI接口层框架图 相关目录下源代码目录结构如下所示 /drivers/peripheral/input ├── hal # input模块的hal层代码 │ └── include # input模块hal层内部的头文件 │ └── src # input模块hal层代码的具体实现 ├── interfaces # input模块对上层服务提供的驱动能力接口 │ └── include # input模块对外提供的接口定义 ├── test # input模块的测试代码 │ └── unittest # input模块的单元测试代码 TP HDF驱动适配 TP驱动涉及的文件及目录 dayu200平台默认支持GT5688这颗TP IC。 开发板移植touch驱动涉及的文件及目录 1、 Makefile文件 drivers\adapter\khdf\linux\model\input\Makefile 2、 vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs 3、 vendor\hihope\rk3568\hdf_config\khdf\input\input_config.hcs 4、 drivers\framework\model\input\driver\touchscreen TP驱动的适配涉及TP驱动和hcs配置 tp驱动的适配依赖hdf的input模型hdf的input模型提供了TPKEYHID等场景的设备注册管理数据转发层hcs解析等场景的支持能力。hdf的input模型可大致抽象为驱动管理层、公共驱动层以及器件驱动三层。 从功能的角度看hdf input模块的框架如下 因为hdf input模型的高度抽象集成TP驱动的适配驱动主要涉及器件驱动层的适配。 在适配前需要先明确tp所需要的的资源。 对于硬件资源tp模组需要主机上的如下资源 1.中断引脚 2.Reset引脚 3.使用的哪一组i2c从设备的地址是什么 4.TP的初始化固件这个通常由IC厂商提供 5.触摸屏的分辨率 对于软件资源在hdf上适配tp需要依赖如下几个hdf基础模组 1.Hdf gpio子系统 用于设置gpio pin脚以及一些中断资源 2.Hdf i2c 子系统 用于进行i2c通信 3.Input模型 器件驱动主要围绕如下结构体展开 static struct TouchChipOps g_gt911ChipOps {.Init ChipInit,.Detect ChipDetect,.Resume ChipResume,.Suspend ChipSuspend,.DataHandle ChipDataHandle,.UpdateFirmware UpdateFirmware,.SetAbility SetAbility, }; ChipInit负责器件驱动的初始化动作 ChipDetect负责初始化后的器件有效性检测 SetAbility设置按键属性 ChipDataHandle负责解析键值 UpdateFirmware负责升级固件 ChipSuspend负责器件的休眠 ChipResume负责器件的唤醒 按照器件的特性实现如上接口回调并将该结构体注册进input模型即可 HCS 配置 device_info.hcs中加入新的器件节点 device_touch_chip :: device {device0 :: deviceNode {policy 0;priority 180;preload 0;//0表示默认加载permission 0660;moduleName HDF_TOUCH_GT911;//需要和器件driver中保持一致serviceName hdf_touch_gt911_service;deviceMatchAttr zsj_gt911_5p5;}}input_config.hcs中加入器件的特性 chipConfig {template touchChip {match_attr ;chipName gt911;vendorName zsj;chipInfo AAAA11222; // 4-ProjectName, 2-TP IC, 3-TP Module/* 0:i2c 1:spi*/busType 0;deviceAddr 0x5D;/* 0:None 1:Rising 2:Failing 4:High-level 8:Low-level */irqFlag 2;maxSpeed 400;chipVersion 0; //parse Coord TypeApowerSequence {/* [type, status, dir , delay]type 0:none 1:vcc-1.8v 2:vci-3.3v 3:reset 4:intstatus 0:off or low 1:on or high 2:no opsdir 0:input 1:output 2:no opsdelay meanings delay xms, 20: delay 20ms*/powerOnSeq [4, 0, 1, 5,3, 0, 1, 10,3, 1, 1, 60,4, 2, 0, 50];suspendSeq [3, 0, 2, 10];resumeSeq [3, 1, 2, 10];powerOffSeq [3, 0, 2, 10,1, 0, 2, 20];}} 显示适配 显示适配需要完成的工作图形服务HDI接口适配、GPU适配、LCD驱动适配 显示HDI 显示HDI对图形服务提供显示驱动能力包括显示图层的管理、显示内存的管理及硬件加速等。 显示HDI需要适配两部分gralloc 和 display_device。 gralloc适配 gralloc模块提供显示内存管理功能OpenHarmony提供了使用与Hi3516DV300参考实现厂商可根据实际情况参考适配该实现基于drm开发。 drm设备节点定义在//drivers_peripheral/display/hal/default_standard/srd/display_gralloc/display_gralloc_gbm.c文件中可根据实际情况修改 const char *g_drmFileNode /dev/dri/card0;该实现中存在一个海思的私有ioctl命令码 DRM_IOCTL_HISILICON_GEM_FD_TO_PHYADDR 定义在//drivers_peripheral/display/hal/default_standard/src/display_gralloc/hisilicon_drm.h 文件中 在//drivers_peripheral/display/hal/default_standard/src/display_gralloc/display_gralloc_gbm.c文件中调用属于海思的私有功能适配时根据实际情况修改 ...InitBufferHandle(bo, fd, info, priBuffer);priBuffer-hdl.phyAddr GetPhysicalAddr(grallocManager-drmFd, fd);*buffer priBuffer-hdl; ...display device适配 display device模块提供显示设备管理、layer管理、硬件加速等功能。 OpenHarmony提供了 基于drm的Hi3516DV300芯片的参考实现,该实现默认支持硬件合成 如开发板不支持硬件合成需要在drm_display.cpp文件中跳过gfx的初始化 drivers_peripheral/blob/master/display/hal/default_standard/src/display_device/drm/drm_display.cpp int32_t DrmDisplay::Init() {......ret HdiDisplay::Init();DISPLAY_CHK_RETURN((ret ! DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE(init failed));auto preComp std::make_uniqueHdiGfxComposition();DISPLAY_CHK_RETURN((preComp nullptr), DISPLAY_FAILURE,DISPLAY_LOGE(can not new HdiGfxComposition errno %{public}d, errno));ret preComp-Init(); // gfx初始化这里需要跳过DISPLAY_CHK_RETURN((ret ! DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE(can not init HdiGfxComposition)); // 或者不判断返回值... } 同时在//drivers_peripheral/display/hal/default_standard/src/display_device/hdi_gfx_composition.cpp文件中修改set_layers方法全部使用CPU合成显示 int32_t HdiGfxComposition::SetLayers(std::vectorHdiLayer * layers, HdiLayer clientLayer) {DISPLAY_LOGD(layers size %{public}zd, layers.size());mClientLayer clientLayer;mCompLayers.clear();for (auto layer : layers) {if (CanHandle(*layer)) { #if 0 // CPU合成layer-SetDeviceSelect(COMPOSITION_CLIENT); #elseif ((layer-GetCompositionType() ! COMPOSITION_VIDEO) (layer-GetCompositionType() ! COMPOSITION_CURSOR)) {layer-SetDeviceSelect(COMPOSITION_DEVICE);} else {layer-SetDeviceSelect(layer-GetCompositionType());} #endifmCompLayers.push_back(layer);}}DISPLAY_LOGD(composer layers size %{public}zd, mCompLayers.size());return DISPLAY_SUCCESS; } 测试验证 hello_composer测试模块Rosen图形框架提供的测试程序主要显示流程HDI接口等功能是否正常。默认随系统编译。 代码路径 foundation/graphic/graphic/rosen/samples/composer/ ├── BUILD.gn ├── hello_composer.cpp ├── hello_composer.h ├── layer_context.cpp ├── layer_context.h └── main.cpp具体验证如下 关闭render service service_control stop render_service 关闭 foundation进程 service_control stop foundation 运行hello_composer 测试相关接口 ./hello_composer devicetest测试HDI显示模块提供的测试模块主要测试HDI接口、显示buffer、驱动等能力测试时也需要关闭render service和 foundation进程。 代码路径/drivers/peripheral/display/test/unittest/standard ├── BUILD.gn ├── common │ ├── display_test.h │ ├── display_test_utils.cpp │ └── display_test_utils.h ├── display_device │ ├── hdi_composition_check.cpp │ ├── hdi_composition_check.h │ ├── hdi_device_test.cpp │ ├── hdi_device_test.h │ ├── hdi_test_device_common.h │ ├── hdi_test_device.cpp │ ├── hdi_test_device.h │ ├── hdi_test_display.cpp │ ├── hdi_test_display.h │ ├── hdi_test_layer.cpp │ ├── hdi_test_layer.h │ ├── hdi_test_render_utils.cpp │ └── hdi_test_render_utils.h └── display_gralloc├── display_gralloc_test.cpp└── display_gralloc_test.hGPU 编译器clang prebuilts/clang/ohos/linux-x86_64/llvmmusl库 ./build.sh --product-name rk3568 --build-target musl_all 编译完成后会在 out/{product_name}/obj/third_party/musl/usr/lib目录下生成对应的头文件和库 32位对应arm-linux-ohos64位对应aarch64-linux-ohos源码目录 third_party/muslGPU 编译参数参考 TARGET_CFLAGS -marcharmv7-a -mfloat-abisoftfp -mtunegeneric-armv7-a -mfpuneon -mthumb --targetarm-linux-ohosmusl -fPIC -ftls-modelglobal-dynamic -mtls-direct-seg-refs -DUSE_MUSLLCD dayu200平台默认支持一个mipi接口的lcd屏幕 LCD的适配主要依赖于HDF显示模型显示驱动模型基于 HDF 驱动框架、Platform 接口及 OSAL 接口开发可以屏蔽不同内核形态(LiteOS、Linux)差异适用于不同芯片平台为显示屏器件提供统一的驱动平台。 如图为 HDF Display驱动模型层次关系 当前驱动模型主要部署在内核态中向上对接到 Display 公共 hal 层辅助 HDI 的实现。显示驱动通过 Display-HDI 层对图形服务暴露显示屏驱动能力向下对接显示屏 panel 器件驱动屏幕正常工作自上而下打通显示全流程通路。 所以LCD的适配主要在于LCD panel器件驱动的适配 器件驱动的适配分为2部分panel驱动和hcs配置 涉及的文件有 drivers/framework/model/display/driver/panelvendor/hihope/rk3568/hdf_config/khdf/device_infovendor/hihope/rk3568/hdf_config/khdf/inputpanel驱动 器件驱动主要围绕如下接口展开 struct PanelData {struct HdfDeviceObject *object;int32_t (*init)(struct PanelData *panel);int32_t (*on)(struct PanelData *panel);int32_t (*off)(struct PanelData *panel);int32_t (*prepare)(struct PanelData *panel);int32_t (*unprepare)(struct PanelData *panel);struct PanelInfo *info;enum PowerStatus powerStatus;struct PanelEsd *esd;struct BacklightDev *blDev;void *priv; };驱动中在初始化接口中实例化该结构体 panelSimpleDev-panel.init PanelSimpleInit; panelSimpleDev-panel.on PanelSimpleOn; panelSimpleDev-panel.off PanelSimpleOff; panelSimpleDev-panel.prepare PanelSimplePrepare; panelSimpleDev-panel.unprepare PanelSimpleUnprepare;PanelSimpleInit负责panel的软件初始化 PanelSimpleOn负责亮屏 PanelSimpleOff负责灭屏 PanelSimplePrepare负责亮屏的硬件时序初始化 PanelSimpleUnprepare负责灭屏的硬件时序初始化 实例化后使用RegisterPanel接口向display模型注册该panel驱动即可 需要说明的是dayu200上的这款lcd 使用的是DRM显示框架 hcs配置 device4 :: deviceNode {policy 0;priority 100;preload 0;moduleName LCD_PANEL_SIMPLE;}背光 基于HDF框架开发的 背光驱动模型 rk3568背光是通过pwm控制占空比实现的具体使用的是pwm4 原生背光驱动代码路径 linux-5.10/drivers/video/backlight/pwm_bl.c linux-5.10/drivers/video/backlight/backlight.c linux-5.10/drivers/pwm/pwm-rockchip.c c使用HDF框架下的背光驱动需要关闭原生驱动 # CONFIG_BACKLIGHT_PWM is not setHDF实现 代码路径 drivers/framework/model/display/driver/backlight/hdf_bl.c cHDF BL 入口函数 static int32_t BacklightInit(struct HdfDeviceObject *object) {if (object NULL) {HDF_LOGE(%s: object is null!, __func__);return HDF_FAILURE;}HDF_LOGI(%s success, __func__);return HDF_SUCCESS; }struct HdfDriverEntry g_blDevEntry {.moduleVersion 1,.moduleName HDF_BL,.Init BacklightInit,.Bind BacklightBind, };HDF_INIT(g_blDevEntry);代码路径 drivers/framework/model/display/driver/backlight/pwm_bl.cHDF PWM 入口函数 struct HdfDriverEntry g_pwmBlDevEntry {.moduleVersion 1,.moduleName PWM_BL,.Init BlPwmEntryInit, };HDF_INIT(g_pwmBlDevEntry);具体控制背光的接口 static int32_t BlPwmUpdateBrightness(struct BacklightDev *blDev, uint32_t brightness) {int32_t ret;uint32_t duty;struct BlPwmDev *blPwmDev NULL;blPwmDev ToBlDevPriv(blDev);if (blPwmDev NULL) {HDF_LOGE(%s blPwmDev is null, __func__);return HDF_FAILURE;}if (blPwmDev-props.maxBrightness 0) {HDF_LOGE(%s maxBrightness is 0, __func__);return HDF_FAILURE;}if (brightness 0) {return PwmDisable(blPwmDev-pwmHandle);}duty (brightness * blPwmDev-config.period) / blPwmDev-props.maxBrightness;ret PwmSetDuty(blPwmDev-pwmHandle, duty);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: PwmSetDuty failed, ret %d, __func__, ret);return HDF_FAILURE;}return PwmEnable(blPwmDev-pwmHandle); }static struct BacklightOps g_blDevOps {.updateBrightness BlPwmUpdateBrightness, };其实使用的就是HDF PWM 实现的对接内核pwm的接口 在LCD HDF器件驱动注册背光 代码路径 drivers/framework/model/display/driver/panel/ili9881c_boe.cili9881cBoeDev-panel.blDev GetBacklightDev(hdf_pwm); if (ili9881cBoeDev-panel.blDev NULL) {HDF_LOGE(%s GetBacklightDev fail, __func__);goto FAIL; }HCS配置 驱动hcs配置 device_pwm_bl :: device {device0 :: deviceNode {policy 0;priority 95;preload 0;moduleName PWM_BL;deviceMatchAttr pwm_bl_dev;} } device_backlight :: device {device0 :: deviceNode {policy 2;priority 90;preload 0;permission 0660;moduleName HDF_BL;serviceName hdf_bl;} }测试 cat /sys/kernel/debug/pwm 来查看hdf pwm 是否申请到pwm4 申请成功有如下结果 requested 代表申请成功 enabled 代表pwm4使能成功 # cat /sys/kernel/debug/pwmplatform/fe6e0000.pwm, 1 PWM devicepwm-0 ((null) ): requested enabled period: 25000 ns duty: 9705 ns polarity: normalWIFI WIFI HDF化思路 主要参考《OpenHarmony HDF WLAN驱动分析》与使用 这篇文章熟悉HDF WLAN的框架以及需要实现的主要接口包括HDF驱动初始化接口、WLAN控制侧接口集、AP模式接口集、STA模式接口集、网络侧接口集、事件上报接口的实现。 接下来熟悉HCS文件的格式以及HDF WIFI”核心驱动框架的代码启动初始化过程参考hi3881的代码进行改造。 HDF WiFi框架总体框架图 ap6275s驱动代码流程分析 驱动模块初始化流程分析 Ap6275s 是一款SDIO设备WiFi模组驱动使用标准Linux的SDIO设备驱动。内核模块初始化入口module_init()调用dhd_wifi_platform_load_sdio()函数进行初始化工作这里调用wifi_platform_set_power()进行GPIO上电调用dhd_wlan_set_carddetect()进行探测SDIO设备卡最后调用sdio_register_driver(bcmsdh_sdmmc_driver);进行SDIO设备驱动的注册SDIO总线已经检测到WiFi模块设备 根据设备号和厂商号与该设备驱动匹配, 所以立即回调该驱动的bcmsdh_sdmmc_probe()函数这里进行WiFi模组芯片的初始化工作最后创建net_device网络接口wlan0然后注册到Linux内核协议栈中。 l 创建net_device网络接口wlan0对象 dhd_allocate_if()会调用alloc_etherdev()创建net_device对象即wlan0网络接口。 l 将wlan0注册到内核协议栈 调用dhd_register_if()函数这里调用register_netdev(net);将wlan0网络接口注册到协议栈。 整改代码适配HDF WiFi框架 对于系统WiFi功能的使用需要实现AP模式、STA模式、P2P三种主流模式这里使用wpa_supplicant应用程序通过HDF WiFi框架与WiFi驱动进行交互实现STA模式和P2P模式的功能使用hostapd应用程序通过HDF WiFi框架与WiFi驱动进行交互实现AP模式和P2P模式的功能。 Ap6275s WiFi6内核驱动依赖platform能力主要包括SDIO总线的通讯能力与用户态通信依赖HDF WiFi框架的能力在确保上述能力功能正常后即可开始本次WiFi驱动的HDF适配移植工作。本文档基于已经开源的rk3568开源版代码为基础版本来进行此次移植。 适配移植ap6275s WiFi6驱动涉及到的文件和目录如下 1). 编译配置文件 drivers/adapter/khdf/linux/model/network/wifi/Kconfig drivers/adapter/khdf/linux/model/network/wifi/vendor/Makefile 2). WiFi驱动源码目录 原生驱动代码存放于 linux-5.10/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd_wifi6/ 在原生驱动上增加以及修改的代码文件位于 device/hihope/rk3568/wifi/bcmdhd_wifi6/ 目录结构 ./device/hihope/rk3568/wifi/bcmdhd_wifi6/hdf ├── hdf_bdh_mac80211.c ├── hdf_driver_bdh_register.c ├── hdfinit_bdh.c ├── hdf_mac80211_ap.c ├── hdf_mac80211_sta.c ├── hdf_mac80211_sta.h ├── hdf_mac80211_sta_event.c ├── hdf_mac80211_sta_event.h ├── hdf_mac80211_p2p.c ├── hdf_public_ap6275s.h ├── net_bdh_adpater.c ├── net_bdh_adpater.h 其中hdf_bdh_mac80211.c主要对g_bdh6_baseOps所需函数的填充 hdf_mac80211_ap.c主要对g_bdh6_staOps所需函数进行填充hdf_mac80211_sta.c主要对g_bdh6_staOps所需函数进行填充hdf_mac80211_p2p.c主要对g_bdh6_p2pOps所需函数进行填充在openharmony/drivers/framework/include/wifi/wifi_mac80211_ops.h里有对wifi基本功能所需api的说明。 驱动文件编写 HDF WLAN驱动框架由Module、NetDevice、NetBuf、BUS、HAL、Client 和 Message 这七个部分组成。开发者在WiFi驱动HDF适配过程中主要实现以下几部分功能 适配HDF WLAN框架的驱动模块初始化 代码流程框图如下 代码位于device/hihope/rk3568/wifi/bcmdhd_wifi6/hdf_driver_bdh_register.c struct HdfDriverEntry g_hdfBdh6ChipEntry {.moduleVersion 1,.Bind HdfWlanBDH6DriverBind,.Init HdfWlanBDH6ChipDriverInit,.Release HdfWlanBDH6ChipRelease,.moduleName HDF_WLAN_CHIPS }; HDF_INIT(g_hdfBdh6ChipEntry);在驱动初始化时会实现SDIO主控扫描探卡、WiFi芯片初始化、主接口的创建和初始化等工作。 2.HDF WLAN Base控制侧接口的实现 代码位于hdf_bdh_mac80211.c static struct HdfMac80211BaseOps g_bdh6_baseOps {.SetMode BDH6WalSetMode,.AddKey BDH6WalAddKey,.DelKey BDH6WalDelKey,.SetDefaultKey BDH6WalSetDefaultKey,.GetDeviceMacAddr BDH6WalGetDeviceMacAddr,.SetMacAddr BDH6WalSetMacAddr,.SetTxPower BDH6WalSetTxPower,.GetValidFreqsWithBand BDH6WalGetValidFreqsWithBand,.GetHwCapability BDH6WalGetHwCapability,.SendAction BDH6WalSendAction,.GetIftype BDH6WalGetIftype, };上述实现的接口供STA、AP、P2P三种模式中所调用。 3.HDF WLAN STA模式接口的实现 STA模式调用流程图如下 代码位于hdf_mac80211_sta.c struct HdfMac80211STAOps g_bdh6_staOps {.Connect HdfConnect,.Disconnect HdfDisconnect,.StartScan HdfStartScan,.AbortScan HdfAbortScan,.SetScanningMacAddress HdfSetScanningMacAddress, };HDF WLAN AP模式接口的实现 AP模式调用流程图如下 代码位于hdf_mac80211_ap.c struct HdfMac80211APOps g_bdh6_apOps {.ConfigAp WalConfigAp,.StartAp WalStartAp,.StopAp WalStopAp,.ConfigBeacon WalChangeBeacon,.DelStation WalDelStation,.SetCountryCode WalSetCountryCode,.GetAssociatedStasCount WalGetAssociatedStasCount,.GetAssociatedStasInfo WalGetAssociatedStasInfo }; 5 HDF WLAN P2P模式接口的实现 P2P模式调用流程图如下 struct HdfMac80211P2POps g_bdh6_p2pOps {.RemainOnChannel WalRemainOnChannel,.CancelRemainOnChannel WalCancelRemainOnChannel,.ProbeReqReport WalProbeReqReport,.AddIf WalAddIf,.RemoveIf WalRemoveIf,.SetApWpsP2pIe WalSetApWpsP2pIe,.GetDriverFlag WalGetDriverFlag, }; 6 HDF WLAN框架事件上报接口的实现 WiFi驱动需要通过上报事件给wpa_supplicant和hostapd应用程序比如扫描热点结果上报新STA终端关联完成事件上报等等HDF WLAN事件上报的所有接口请参考drivers/framework/include/wifi/hdf_wifi_event.h 事件上报HDF WLAN接口主要有 头文件 hdf_wifi_event.h接口名称功能描述HdfWifiEventNewSta()上报一个新的sta事件HdfWifiEventDelSta上报一个删除sta事件HdfWifiEventInformBssFrame上报扫描Bss事件HdfWifiEventScanDone上报扫描完成事件HdfWifiEventConnectResult上报连接结果事件HdfWifiEventDisconnected上报断开连接事件HdfWifiEventMgmtTxStatus上报发送状态事件HdfWifiEventRxMgmt上报接受状态事件HdfWifiEventCsaChannelSwitch上报Csa频段切换事件HdfWifiEventTimeoutDisconnected上报连接超时事件HdfWifiEventEapolRecv上报Eapol接收事件HdfWifiEventResetResult上报wlan驱动复位结果事件HdfWifiEventRemainOnChannel上报保持信道事件HdfWifiEventCancelRemainOnChannel上报取消保持信道事件 所有关键问题总结 调试AP模块时启动AP模式的方法 调试AP模块时无法正常开启AP功能的解决方法 需要使用到busybox和hostapd配置ap功能操作步骤如下 ifconfig wlan0 up ifconfig wlan0 192.168.12.1 netmask 255.255.255.0 busybox udhcpd /data/udhcpd.conf ./hostapd -d /data/hostapd.conf调试STA模块时启动STA模式的方法 wpa_supplicant -iwlan0 -c /data/l2tool/wpa_supplicant.conf -d ./busybox udhcpc -i wlan0 -s /data/l2tool/dhcpc.sh扫描热点事件无法上报到wap_supplicant的解决办法 wpa_supplicant 这个应用程序启动时不能加 -B参数后台启动-B后台启动的话调用poll()等待接收事件的线程会退出所以无法接收上报事件 wpa_supplicant -iwlan0 -c /data/wpa_supplicant.conf 这样后台启动就可以了。 wpa2psk方式无法认证超时问题解决方法 分析流程发现 hostapd没有接收到WIFI_WPA_EVENT_EAPOL_RECV 13这个事件原来是驱动没有将接收到的EAPOL报文通过HDF WiFi框架发送给hostapd进程在驱动接收报文后调用netif_rx()触发软中断前将EAPOL报文发送给HDF WiFi框架认证通过了。 P2P模式连接不成功问题定位分析 在调试P2P连接接口时发现手机P2P直连界面总是处于已邀请提示无法连接成功通过抓取手机和WiFi模组正常连接成功报文和HDF适配后连接失败的报文进行比对在失败的报文组中发现手机侧多回复了一帧ACTION报文提示无效参数然后终止了P2P连接。 最后比对WiFi模组向手机发送的ACTION报文内容发现填充的P2P Device Info的MAC地址值不对如下 正确帧内容 错误帧内容 最后经过分析MAC地址的填充部分代码这个MAC地址是wpa_supplicant 根据p2p0的MAC地址填充的所以将wdev对象即p2p-dev-wlan0的MAC地址更新给p2p0接口二者保持一致即可见代码wl_get_vif_macaddr(cfg, 7, p2p_hnetdev-macAddr);的调用。 连接成功日志 STA模式连接成功日志 WPA: Key negotiation completed with 50:eb:f6:02:8e6:d4 [PTKCCMP GTKCCMP]06 wlan0: State: GROUP_HANDSHAKEc - COMPLETED wlan0: CTRL-E4VENT-CONNECTED - Connection to 50:eb:f6:02:8e:d4 completed 3[id0 id_str] WifiWpaReceived eEapol done AP模式连接成功日志 wlan0: STA 96:27:b3:95:b7:6e IEEE 802.1X: au:thorizing port wlan0: STA 96:27:b3:95:b7:6e WPA: pairwise key handshake completed (RSN) WifiWpaReceiveEapol done P2P模式连接成功日志 P2P: cli_channels: EAPOL: External notificationtion - portValid1 EAPOL: External notification:tion - EAP success1 EAPOL: SUPP_PAE entering state AUTHENTIwCATING EAPOL: SUPP_BE enterilng state SUCCESS EAP: EAP ent_ering state DISABLED EAPOL: SUPP_PAE entering state AUTHENTICATED EAPOL:n Supplicant port status: Authoorized EAPOL: SUPP_BE entertaining IDLE WifiWpaReceiveEapol donepleted - resultSUCCESS\# ifconfig lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope: HostUP LOOPBACK RUNNING MTU:65536 Metric:1RX packets:12 errors:0 dropped:0 overruns:0 frame:0 TX packets:12 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:565 TX bytes:565 wlan0 Link encap:Ethernet HWaddr 10:2c:6b:11:61:e0 Driver bcmsdh_sdmmcinet6 addr: fe80::122c:6bff:fe11:61e0/64 Scope: LinkUP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 TX bytes:0 p2p0 Link encap:Ethernet HWaddr 12:2c:6b:11:61:e0inet6 addr: fe80::102c:6bff:fe11:61e0/64 Scope: LinkUP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 TX bytes:0 p2p-p2p0-0 Link encap:Ethernet HWaddr 12:2c:6b:11:21:e0 Driver bcmsdh_sdmmcinet6 addr: fe80::102c:6bff:fe11:21e0/64 Scope: LinkUP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:0 errors:0 dropped:9 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 TX bytes:0 BT HCI接口 蓝牙整体硬件架构上分为主机计算机或MCU和主机控制器实际蓝牙芯片组两部分主机和控制器之间的通信遵循主机控制器接口HCI如下所示 HCI定义了如何交换命令事件异步和同步数据包。异步数据包ACL用于数据传输而同步数据包SCO用于带有耳机和免提配置文件的语音。 硬件连接 从RK3568芯片描述中看该芯片并不没有集成WIFI/蓝牙功能都需要外接蓝牙芯片才能支持蓝牙功能这也符合上述逻辑架构。那主机和控制器之间物理具体怎么连接呢查看开发板规格书可以看的更清楚 其中28-36号管脚就是UART串口同时还可以看到有几个管脚分别做电源和休眠控制。 蓝牙VENDORLIB适配 vendorlib是什么 vendorlib部署在主机侧可以认为是主机侧对蓝牙芯片驱动层屏蔽不同蓝牙芯片的技术细节。从代码层面解读其主要功能有两个 1、为协议栈提供蓝牙芯片之间的通道串口的文件描述符 2、提供特定芯片的具体控制方法 代码层面解读vendorlib bt_vendor_lib.h 路径 foundation/communication/bluetooth/services/bluetooth_standard/hardware/include该文件定义了协议栈和vendor_lib交互接口分为两组 1、 vendorlib实现协议栈调用 typedef struct {/*** Set to sizeof(bt_vendor_interface_t)*/size_t size;/*** Caller will open the interface and pass in the callback routines* to the implementation of this interface.*/int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char* local_bdaddr);/*** Vendor specific operations*/int (*op)(bt_opcode_t opcode, void* param);/*** Closes the interface*/void (*close)(void); } bt_vendor_interface_t;协议栈启动时的基本流程如下 1.1、协议栈动态打开libbt_vendor.z.so并调用init函数初始化vendorlib 1.2、协议栈调用op函数分别调用BT_OP_POWER_ON、BT_OP_HCI_CHANNEL_OPEN、BT_OP_INIT三个opcode原则上BT_OP_INIT成功后说明芯片初始化完成。 2、协议栈实现vendorlib调用回调函数 typedef struct {/*** set to sizeof(bt_vendor_callbacks_t)*/size_t size;/* notifies caller result of init request */init_callback init_cb;/* buffer allocation request */malloc_callback alloc;/* buffer free request */free_callback dealloc;/* hci command packet transmit request */cmd_xmit_callback xmit_cb; } bt_vendor_callbacks_t;init_cb在BT_OP_INIT完成后调用 alloc/dealloc用于发送HCI消息时申请/释放消息控件 xmit_cb发送HCI Commands vendor_lib实现的几个重要函数 1、 init函数 static int init(const bt_vendor_callbacks_t *p_cb, unsigned char *local_bdaddr) {/* * ... */userial_vendor_init();upio_init();vnd_load_conf(VENDOR_LIB_CONF_FILE);/* store reference to user callbacks */bt_vendor_cbacks (bt_vendor_callbacks_t *)p_cb;/* This is handed over from the stack */return memcpy_s(vnd_local_bd_addr, BD_ADDR_LEN, local_bdaddr, BD_ADDR_LEN); } cvendorlib被调用的第一个函数vendorlib保存好协议栈的callback和mac地址即可。 2、 BT_OP_POWER_ON对应处理 观名知意这个操作理论上需要拉高电源管脚电平该函数中使用rfill设备来处理并没有直接调用驱动拉高电平 int upio_set_bluetooth_power(int on) {int sz;int fd -1;int ret -1;char buffer 0;switch (on) {case UPIO_BT_POWER_OFF:buffer 0;break;case UPIO_BT_POWER_ON:buffer 1;break;default:return 0;}/* check if we have rfkill interface */if (is_rfkill_disabled()) {return 0;}if (rfkill_id -1) {if (init_rfkill()) {return ret;}}fd open(rfkill_state_path, O_WRONLY);if (fd 0) {return ret;}sz write(fd, buffer, 1);/* ... */return ret; }3、BT_OP_HCI_CHANNEL_OPEN对应处理 case BT_OP_HCI_CHANNEL_OPEN: { // BT_VND_OP_USERIAL_OPENint(*fd_array)[] (int(*)[])param;int fd, idx;fd userial_vendor_open((tUSERIAL_CFG *)userial_init_cfg);if (fd ! -1) {for (idx 0; idx HCI_MAX_CHANNEL; idx)(*fd_array)[idx] fd;retval 1;}/* retval contains numbers of open fd of HCI channels */break;userial_vendor_open函数打开串口设备UART得到文件描述符(fd)通过op的参数param返回该fd 该串口设备在系统中的名字应该在开发板中预定义了本次开发板上设备为/dev/ttyS8 4、BT_OP_INIT对应处理 该操作码要求对蓝牙芯片进行初始化具体要进行的处理和蓝牙芯片强相关。以本次调测的AP6257S芯片为例初始化过程中主要是下发蓝牙固件。 初始化结束后必须调用init_cb回调函数参见bt_vendor_callbacks_t通知协议栈初始化结果否则会阻塞协议栈线程导致蓝牙相关功能无法正常使用。协议栈的具体处理如下 协议栈调用BT_OP_INIT后会等待信号量该信号量由init_cb函数置位 static int HciInitHal() {int result BT_NO_ERROR;g_waitHdiInit SemaphoreCreate(0);int ret g_hdiLib-hdiInit(g_hdiCallbacks);if (ret SUCCESS) {SemaphoreWait(g_waitHdiInit);} }vendorlib移植问题 1、 vendorlib的so命名 vendorlib必须是libbt_vendor.z.so因为协议栈打开动态链接库就是这个名字 2、 固件问题 开发时一定要关注芯片固件有些蓝牙芯片可能无需升级固件有些则必须升级固件本次AP6257S适配过程中最开始没有下发固件导致蓝牙接收信号很差。固件下发时需要注意如下两点 2.1、对于AP6257S芯片因为蓝牙芯片内并没有类似flash存储要求芯片上下电后必须重新下发 2.2、按照芯片本身的要求处理最好能找到厂商的参考代码以Broadcom系列芯片为例其固件下发过程比较复杂通过一个状态机驱动共如下9个状态 / Hardware Configuration State */ enum {HW_CFG_START 1,HW_CFG_SET_UART_CLOCK,HW_CFG_SET_UART_BAUD_1,HW_CFG_READ_LOCAL_NAME,HW_CFG_DL_MINIDRIVER,HW_CFG_DL_FW_PATCH,HW_CFG_SET_UART_BAUD_2,HW_CFG_SET_BD_ADDR,HW_CFG_READ_BD_ADDR };在收到BT_OP_INIT后初始化状态机然后发送HCI_REST命令切换状态为HW_CFG_START void hw_config_start(void) {HC_BT_HDR *p_buf NULL;uint8_t *p;hw_cfg_cb.state 0;hw_cfg_cb.fw_fd -1;hw_cfg_cb.f_set_baud_2 FALSE;if (bt_vendor_cbacks) {p_buf (HC_BT_HDR *)bt_vendor_cbacks-alloc(BT_HC_HDR_SIZE HCI_CMD_PREAMBLE_SIZE);}if (p_buf) {p_buf-event MSG_STACK_TO_HC_HCI_CMD;p_buf-offset 0;p_buf-layer_specific 0;p_buf-len HCI_CMD_PREAMBLE_SIZE;p (uint8_t *)(p_buf 1);UINT16_TO_STREAM(p, HCI_RESET);*p 0;hw_cfg_cb.state HW_CFG_START;bt_vendor_cbacks-xmit_cb(HCI_RESET, p_buf);} else {if (bt_vendor_cbacks) {HILOGE(vendor lib fw conf aborted [no buffer]);bt_vendor_cbacks-init_cb(BTC_OP_RESULT_FAIL);}} }收到芯片返回的HCI_RESET完成事件后继续切换到下一个状态机并发送下一个COMMAND一直到状态机完成固件下发。 3、 关注系统间接口差异 不同系统的接口可能有一些细微差异需要重点关注对比其他系统和OHOS的接口vendorlib调用xmit_cb发送HCI命令的函数定义略有差异 其他系统 /* define callback of the cmd_xmit_cb*The callback function which HCI lib will call with the return of commandcomplete packet. Vendor lib is responsible for releasing the buffer passedin at the p_mem parameter by calling dealloc callout function. */ typedef void (*tINT_CMD_CBACK)(void* p_mem); typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void* p_buf, tINT_CMD_CBACK p_cback);OHOS /**hci command packet transmit callbackVendor lib calls cmd_xmit_cb function in order to send a HCI Commandpacket to BT Controller. *The opcode parameter gives the HCI OpCode (combination of OGF and OCF) ofHCI Command packet. For example, opcode 0x0c03 for the HCI_RESET commandpacket. */typedef uint8_t (*cmd_xmit_callback)(uint16_t opcode, void* p_buf);也就是说vendorlib中发送命令后其他系统会直接调用callback通知芯片返回的消息OHOS则是通过BT_OP_EVENT_CALLBACK操作码参见bt_opcode_t定义通知芯片返回的消息vendorlib需要解析报文中的消息码确认芯片是处理的哪个消息然后调用对应的处理函数。 void hw_process_event(HC_BT_HDR *p_buf) {uint16_t opcode;uint8_t *p (uint8_t *)(p_buf 1) HCI_EVT_CMD_CMPL_OPCODE;STREAM_TO_UINT16(opcode, p);switch (opcode) {case HCI_VSC_WRITE_BD_ADDR:#if (USE_CONTROLLER_BDADDR TRUE)case HCI_READ_LOCAL_BDADDR:#endifcase HCI_READ_LOCAL_NAME:case HCI_VSC_DOWNLOAD_MINIDRV:case HCI_VSC_WRITE_FIRMWARE:case HCI_VSC_LAUNCH_RAM:case HCI_RESET:case HCI_VSC_WRITE_UART_CLOCK_SETTING:case HCI_VSC_UPDATE_BAUDRATE:hw_config_cback(p_buf);break;另外OHOS返回的是发送消息的字节数0为发送失败和其他系统接口的返回值也不同 4、 snoop日志 其他系统中记录了HCI交互消息OHOS同样有记录OHOS系统生成文件为/data/log/bluetooth/snoop.log通过wireshark或其它报文分析工具可以看到Host和Controller之间的交互流程有助于问题分析 Sensor 基于HDFHardware Driver Foundation驱动框架开发的Sensor驱动模型 rk3568 支持accel sensor整体的驱动框架openharmony 主线已经具备只需要实现具体的器件驱动即可。 mcx5566xa HDF驱动实现 RK3568平台支持加速度传感器型号是MXC6655XA,具体配置可以查看该器件的datasheet。 移植HDF前需要确认内核该sensor的编译使能是关闭的。 配置文件路径kernel/linux/config/linux-5.10/arch/arm64/configs/rk3568_standard_defconfig # CONFIG_GS_MXC6655XA is not set代码路径 drivers/framework/model/sensor/driver/chipset/accel/accel_mxc6655xa.c drivers/framework/model/sensor/driver/chipset/accel/accel_mxc6655xa.h编译宏 CONFIG_DRIVERS_HDF_SENSOR_ACCEL_MXC6655XAyMxc6655xa 加速度计驱动入口函数实现 struct HdfDriverEntry g_accelMxc6655xaDevEntry {.moduleVersion 1,.moduleName HDF_SENSOR_ACCEL_MXC6655XA,.Bind Mxc6655xaBindDriver,.Init Mxc6655xaInitDriver,.Release Mxc6655xaReleaseDriver, };HDF_INIT(g_accelMxc6655xaDevEntry);接下来就是差异化适配函数 struct AccelOpsCall { int32_t (*Init)(struct SensorCfgData *data); int32_t (*ReadData)(struct SensorCfgData *data); };获取x, y, z三轴数据接口 int32_t ReadMxc6655xaData(struct SensorCfgData *cfg, struct SensorReportEvent *event) {int32_t ret;struct AccelData rawData { 0, 0, 0 };static int32_t tmp[ACCEL_AXIS_NUM];CHECK_NULL_PTR_RETURN_VALUE(cfg, HDF_ERR_INVALID_PARAM);CHECK_NULL_PTR_RETURN_VALUE(event, HDF_ERR_INVALID_PARAM);ret ReadMxc6655xaRawData(cfg, rawData, event-timestamp);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: MXC6655XA read raw data failed, __func__);return HDF_FAILURE;}event-sensorId SENSOR_TAG_ACCELEROMETER;event-option 0;event-mode SENSOR_WORK_MODE_REALTIME;rawData.x rawData.x * MXC6655XA_ACC_SENSITIVITY_2G;rawData.y rawData.y * MXC6655XA_ACC_SENSITIVITY_2G;rawData.z rawData.z * MXC6655XA_ACC_SENSITIVITY_2G;tmp[ACCEL_X_AXIS] (rawData.x * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;tmp[ACCEL_Y_AXIS] (rawData.y * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;tmp[ACCEL_Z_AXIS] (rawData.z * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;ret SensorRawDataToRemapData(cfg-direction, tmp, sizeof(tmp) / sizeof(tmp[0]));if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: MXC6655XA convert raw data failed, __func__);return HDF_FAILURE;}event-dataLen sizeof(tmp);event-data (uint8_t *)tmp;return ret; }初始化 static int32_t InitMxc6655xa(struct SensorCfgData *data) {int32_t ret;CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);ret SetSensorRegCfgArray(data-busCfg, data-regCfgGroup[SENSOR_INIT_GROUP]);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: MXC6655XA sensor init config failed, __func__);return HDF_FAILURE;}return HDF_SUCCESS; }hcs配置 Mxc6655xa accel sensor 驱动HCS配置 device_sensor_mxc6655xa :: device {device0 :: deviceNode {policy 1;priority 120;preload 0;permission 0664;moduleName HDF_SENSOR_ACCEL_MXC6655XA;serviceName hdf_accel_mxc6655xa;deviceMatchAttr hdf_sensor_accel_mxc6655xa_driver;} }Mxc6655xa accel sensor 寄存器组配置信息 #include ../sensor_common.hcs root {accel_mxc6655xa_chip_config : sensorConfig {match_attr hdf_sensor_accel_mxc6655xa_driver;sensorInfo :: sensorDeviceInfo {sensorName accelerometer;vendorName memsi_mxc6655xa; // max string length is 16 bytessensorTypeId 1; // enum SensorTypeTagsensorId 1; // user define sensor idpower 230;}sensorBusConfig :: sensorBusInfo {busType 0; // 0:i2c 1:spibusNum 5;busAddr 0x15;regWidth 1; // 1byte}sensorIdAttr :: sensorIdInfo {chipName mxc6655xa;chipIdRegister 0x0f;chipIdValue 0x05;}sensorDirection {direction 5; // chip direction range of value:0-7/* sign 1:negative 0:positivemap 0:AXIS_X 1:AXIS_Y 2:AXIS_Z*//* sign[AXIS_X], sign[AXIS_Y], sign[AXIS_Z], map[AXIS_X], map[AXIS_Y], map[AXIS_Z] */convert [0, 0, 0, 0, 1, 2,1, 0, 0, 1, 0, 2,0, 0, 1, 0, 1, 2,0, 1, 0, 1, 0, 2,1, 0, 1, 0, 1, 2,0, 0, 1, 1, 0, 2,0, 1, 1, 0, 1, 2,1, 1, 1, 1, 0, 2];}sensorRegConfig {/* regAddr: register addressvalue: config register valuelen: size of valuemask: mask of valuedelay: config register delay time (ms)opsType: enum SensorOpsType 0-none 1-read 2-write 3-read_check 4-update_bitcalType: enum SensorBitCalType 0-none 1-set 2-revert 3-xor 4-left shift 5-right shiftshiftNum: shift bitsdebug: 0-no debug 1-debugsave: 0-no save 1-save*//* regAddr, value, mask, len, delay, opsType, calType, shiftNum, debug, save */initSeqConfig [0x7e, 0xb6, 0xff, 1, 5, 2, 0, 0, 0, 0,0x7e, 0x10, 0xff, 1, 5, 2, 0, 0, 0, 0];enableSeqConfig [0x7e, 0x11, 0xff, 1, 5, 2, 0, 0, 0, 0,0x41, 0x03, 0xff, 1, 0, 2, 0, 0, 0, 0,0x40, 0x08, 0xff, 1, 0, 2, 0, 0, 0, 0];disableSeqConfig [0x7e, 0x10, 0xff, 1, 5, 2, 0, 0, 0, 0];}} }测试 UT测试可以获取到sensor的三轴数据 测试代码路径 drivers/peripheral/sensor/test/unittest/common/hdf_sensor_test.cpp编译UT代码命令 ./build.sh --product-name rk3568 --build-target hdf_test_sensor将hdf_test_sensor.bin push到system/bin目录添加执行权限执行 有如下结果代表sensor 测试成功 SensorTestDataCallback enter sensor id :[1], data[1]: 0.001877 sensor id :[1], data[2]: 0.160823 sensor id :[1], data[3]: 0.046122Vibrator vibrator 模型 Vibrator驱动模型主要包含Vibrator传感器相关的HDI接口与实现提供Vibrator HDIHardware Driver Interface能力接口支持静态HCS配置的时间序列和动态配置持续时间两种振动效果。调用StartOnce接口动态配置持续振动时间调用StartEffect接口启动静态配置的振动效果。 图 1 Vibrator驱动模型图 rk3568 支持线性马达整体的驱动框架openharmony 主线已经具备只需要实现具体的器件驱动即可。 HDF驱动实现 代码路径 drivers/framework/model/misc/vibrator/driver/chipset/vibrator_linear_driver.clinear Vibrator加速度计驱动入口函数实现 struct HdfDriverEntry g_linearVibratorDriverEntry {.moduleVersion 1,.moduleName HDF_LINEAR_VIBRATOR,.Bind BindLinearVibratorDriver,.Init InitLinearVibratorDriver,.Release ReleaseLinearVibratorDriver, };HDF_INIT(g_linearVibratorDriverEntry);hcs配置 驱动hcs配置 vibrator :: host {hostName vibrator_host;device_vibrator :: device {device0 :: deviceNode {policy 2;priority 100;preload 0;permission 0664;moduleName HDF_VIBRATOR;serviceName hdf_misc_vibrator;deviceMatchAttr hdf_vibrator_driver;}}device_linear_vibrator :: device {device0 :: deviceNode {policy 1;priority 105;preload 0;permission 0664;moduleName HDF_LINEAR_VIBRATOR;serviceName hdf_misc_linear_vibrator;deviceMatchAttr hdf_linear_vibrator_driver;}}}线性马达器件hcs配置 root {linearVibratorConfig {boardConfig {match_attr hdf_linear_vibrator_driver;vibratorChipConfig {busType 1; // 0:i2c 1:gpiogpioNum 154;startReg 0;stopReg 0;startMask 0;}}} }UT测试 测试代码路径 drivers/peripheral/misc/vibrator/test/unittest/common/hdf_vibrator_test.cpp c编译UT代码命令 ./build.sh --product-name rk3568 --build-target hdf_test_vibrator c将hdf_test_vibrator.bin push到system/bin目录添加执行权限执行 [ RUN ] HdfVibratorTest.CheckVibratorInstanceIsEmpty [ OK ] HdfVibratorTest.CheckVibratorInstanceIsEmpty (0 ms) [ RUN ] HdfVibratorTest.PerformOneShotVibratorDuration001 [ OK ] HdfVibratorTest.PerformOneShotVibratorDuration001 (2001 ms) [ RUN ] HdfVibratorTest.ExecuteVibratorEffect001 [ OK ] HdfVibratorTest.ExecuteVibratorEffect001 (5001 ms)经常有很多小伙伴抱怨说不知道学习鸿蒙开发哪些技术不知道需要重点掌握哪些鸿蒙应用开发知识点 为了能够帮助到大家能够有规划的学习这里特别整理了一套纯血版鸿蒙HarmonyOS Next全栈开发技术的学习路线包含了鸿蒙开发必掌握的核心知识要点内容有ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等鸿蒙HarmonyOS NEXT技术知识点。 《鸿蒙 (Harmony OS)开发学习手册》共计892页:https://gitcode.com/HarmonyOS_MN/733GH/overview 如何快速入门 1.基本概念 2.构建第一个ArkTS应用 3.…… 开发基础知识: 1.应用基础知识 2.配置文件 3.应用数据管理 4.应用安全管理 5.应用隐私保护 6.三方应用调用管控机制 7.资源分类与访问 8.学习ArkTS语言 9.…… 基于ArkTS 开发 1.Ability开发 2.UI开发 3.公共事件与通知 4.窗口管理 5.媒体 6.安全 7.网络与链接 8.电话服务 9.数据管理 10.后台任务(Background Task)管理 11.设备管理 12.设备使用信息统计 13.DFX 14.国际化开发 15.折叠屏系列 16.…… 鸿蒙开发面试真题含参考答案:https://gitcode.com/HarmonyOS_MN/733GH/overview OpenHarmony 开发环境搭建 《OpenHarmony源码解析》:https://gitcode.com/HarmonyOS_MN/733GH/overview 搭建开发环境Windows 开发环境的搭建Ubuntu 开发环境搭建Linux 与 Windows 之间的文件共享……系统架构分析构建子系统启动流程子系统分布式任务调度子系统分布式通信子系统驱动子系统…… OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview
http://www.hkea.cn/news/14471599/

相关文章:

  • 可以自学做网站吗网页设计ppt演讲
  • 珠海房地产网站建设墟沟企业建站价格表
  • 网站开发策划书宁波网站关键词优化代码
  • 介绍学校网站怎么做wordpress 下载文件插件
  • 彩票网站开发软件网站开发公司需要那些硬件设备
  • 网站做优化有什么用吗云主机建设网站
  • 家具flash网站模板下载怎么做刷业网站
  • 做网站不会写代码网络舆情监测系统软件
  • 做风投要关注哪些网站有没有做美食的规模网站
  • 成都网站建设哪家专业而且比较便宜网站需求建设关系书
  • 网站建设倒计时自建网站怎么关闭
  • 福清市住房和城乡建设局网站wordpress文章乱码
  • asp网站模板中国互联网协会副会长名单
  • 虚拟主机对网站seo有哪些影响最好的wordpress教程
  • 网站设计的国际专业流程网站买源代码
  • 网站开发的在线支付功能wordpress sql脚本
  • 淮安网站制作设计外链屏蔽逐步解除
  • 建网站哪便宜深圳外贸公司联系电话
  • 查询行业信息的网站济南建设工程交易中心
  • 怎么给自己的网站做seo福州微信网站制作
  • 长沙外贸企业网站建设电商网站建设毕业设计
  • 创办网站公司廊坊网站霸屏
  • 自己创造网站上海个人做网站
  • 扬州做网站公司哪家好制作网站公司
  • 论坛类网站开发报价唐山网站建设公司
  • 谷歌网站的设计原则百度排名优化工具
  • 网站建设培训西安深圳华强北鬼市
  • 何做好网站建设销售wordpress 子分类文章
  • 网站做广告如何做帐怎么导入wordpress模板
  • 毕业设计 做网站网站建设易网