#夏日挑战赛#初识OpenHarmony蓝牙模块 原创 精华

深开鸿
发布于 2022-7-5 13:50
浏览
4收藏

本文正在参加星光计划3.0–夏日挑战赛
作者:巴延兴

1. 简介

​ 随着现代移动通信和物联网的快速发展,万物互联已经越来越成为一个基本需求,而近距离的无线通信更是在移动设备之间有着及其广泛的应用。蓝牙技术是一种无线数据和语音传输的开放式标准,它是基于低成本的近距离无线连接,为固定和移动设备建立通信的一种近距离无线技术连接。蓝牙技术正广泛运用于汽车领域、工业生产、医疗领域。

1.1 OpenHarmony架构图

​ 蓝牙子系统所属的分布式软总线在整个OpenHarmony系统中的位置在如下红框处:

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

2. 基础知识

2.1 蓝牙概述

​ 蓝牙是一种支持设备短距离通信(一般10m内)的无线电技术,能在包括移动电话、PDA、无线耳机、笔记本电脑、相关外设等众多具有蓝牙模块的设备之间进行短距离无线信息交换,使得数据传输变得更加迅速高效。它是爱立信、IBM等5家公司在1998年联合推出的一项无线通信技术,随后成立的蓝牙技术特殊兴趣组织(SIG)来负责该技术的开发和技术协议的制定,如今全世界已有1800多家公司加盟该组织。

​ 蓝牙工作在全球通用的2.4GHz ISM(即工业、科学、医学)频段,使用IEEE802.15协议。作为一种的短距离无线通信技术,在现在的生活中,正扮演着极其重要的角色。当然,在操作系统中,蓝牙模块正扮演着必不可少的基础功能。

2.2 蓝牙架构图

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

​ 在蓝牙技术中,有**Application**,**Host**和**Controller**三个角色。这三个角色可以位于不同的设备,也可以位于同一个设备上。在一个系统中,Host只有一个,但Controller可以一个也可以有多个。

​ Application:由不同的Profiles来限定,蓝牙系统中的应用程序互操作性是由profiles完成的。profiles定义了蓝牙系统中从PHY到L2CAP以及核心规范之外的任何其他协议所需的每层功能和特性。配置文件定义了层之间的**垂直**交互以及**设备之间特定层**的点对点交互。此外,应用程序的**行为**和**数据格式**也由profiles定义。

​ Host:负责在逻辑链路的基础上,进行更为友好的封装,这样就可以屏蔽掉蓝牙技术的细节,让Bluetooth Application更为方便的使用。

​ Controller:负责定义RF、Baseband等底层的规范,并在这之上抽象出用于通信的逻辑链路。

2.3 蓝牙子系统代码架构图

​ 下图为OpenHamony蓝牙子系统的代码结构,图中可以看到从上层到底层的整个过程。

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区
​ APP:蓝牙应用程序,即使用蓝牙API的程序,一般是在设备的settings里实现。通过调用bluetooth的interfaces下的对应接口来实现应用程序的功能。

​ bluetooth:蓝牙框架层,主要包括interfaces和services,本篇主要针对该部分做详细解读。

​ HDF:硬件驱动框架,bluetooth的设备驱动的开发是基于该框架的基础上,结合操作系统适配层(OSAL)和平台驱动接口(比如I2C/SPI/UART总线等平台资源)能力,屏蔽不同操作系统和平台总线资源差异,实现bluetooth驱动"一次开发,多系统部署"的目标。

​ HardWare:各类具有蓝牙模块硬件实体的硬件设备,如移动电话、PDA、无线耳机、笔记本电脑、相关外设等众多设备。

2.4 蓝牙子系统代码目录

​ bluetooth 框架层的代码目录结构如下:


/foundation/communication/bluetooth

├── interfaces # 接口代码

│ └── innerkits # 系统服务接口存放目录

│ ├── native\_c # C接口存放目录

│ │ └── include # C接口定义目录

│ └── native\_cpp # C++接口存放目录

│── sa\_profile # 蓝牙服务定义目录

│── services # 蓝牙服务代码目录

└── LICENSE # 版权声明文件

​ interfaces,负责向上层应用程序提供相应的功能接口,使应用开发者实现具体蓝牙业务功能,目前只提供c/c++接口。

​ services负责interfaces接口的实现。系统提供C/C++接口定义及服务和协议栈的代码,目前提供的只有BLE相关的接口,包括BLE设备GATT相关的操作,以及BLE广播、扫描等功能,其它A2DP,AVRCP,HFP等相关接口在后续增量发布。

​ services部分主要是通过bluetooth_standard目录下的相关模块来实现interfaces接口。相关的模块有common、hardware、external、etc、ipc、stack、service、server。模块间利用c++的相关特性,完成了各自的分层功能,最终实现了蓝牙不同协议的场景功能。代码架构如下:


└── services

├── bluetooth

│   └── BUILD.gn

└── bluetooth\_standard

├── common #定义蓝牙相关的数据结构,供其他子模块调用

├── etc #蓝牙服务的配置文件存放处,蓝牙设备、profile的配置文件

├── external #扩展目录

├── hardware #定义HCI的相关接口供其他子模块调用

├── ipc #进程间通信,不同协议的proxy和stub之间的数据传递等

├── server #主从模式的server端代码存放处

├── service #不同协议的服务接口及实现,供server调用

└── stack #常规stack、list、queue,信号量,互斥量的操作,不同协议栈的相关数据结构的创建、初始化等

2.5 蓝牙子系统协议

​ 蓝牙相关协议栈在stack目录下按照目录进行协议分类,如下:


└── stack

└── src

├── att 属性协议

├── avctp 音视频控制传输协议

├── avdtp 音视频分发协议

├── btm (Bluetooth manage蓝牙配对与链路管理)

├── gap (Generic Access Profile通用访问协议)

├── hci 主机控制接口协议

├── l2cap 逻辑链路控制和适配协议

├── rfcomm 串口仿真协议

├── sdp 服务发现协议

└── smp(Security Manage Protoco蓝牙安全管理协议)

3. 源码分析

​ @ohos.bluetooth.d.ts文件提供了供应用侧调用的接口,我们以最常用的打开蓝牙开关的操作来展示代码的时序流程。

​ 应用侧调用了@ohos.bluetooth.d.ts中示例的enableBluetooth()接口来开启蓝牙,如下:


function enableBluetooth(): boolean;

​ 实际上d.ts中的接口在代码中仅仅只是用来示例,真正起作用的是NAPI的接口EnableBluetooth,该接口对应的文件为napi_bluetooth_host.cpp,如下:


napi\_value EnableBluetooth(napi\_env env, napi\_callback\_info info)

{

HILOGI("EnableBluetooth start");

BluetoothHost \*host = &BluetoothHost::GetDefaultHost();

bool enabled = host-\>EnableBt();

enabled |= host-\>EnableBle();

napi\_value result = nullptr;

napi\_get\_boolean(env, enabled, &result);

HILOGI("EnableBluetooth end");

return result;

}

​ napi接口调用的是BluetoothHost中的EnableBt()和EnableBle()方法分别打开经典蓝牙和低功耗蓝牙开关。我们以打开低功耗蓝牙为例分析代码流程。

3.1 打开低功耗蓝牙代码流程

​ BluetoothHost::EnableBle()接口如下:


bool BluetoothHost::EnableBle()

{

HILOGD("BluetoothHost::Enable BLE starts");

if (!pimpl) {

HILOGE("BluetoothHost::Enable BLE fails: no pimpl");

return false;

}

if (pimpl-\>proxy\_ == nullptr) {

HILOGE("BluetoothHost::Enable fails: no proxy");

return false;

}

return pimpl-\>proxy\_-\>EnableBle();

}

​ 调用的是BluetoothHostProxy中的EnableBle()接口。如下所示。此时已经从interface目录进入到service目录下的ipc目录。


bool BluetoothHostProxy::EnableBle()

{

MessageParcel data;

if (!data.WriteInterfaceToken(BluetoothHostProxy::GetDescriptor())) {

HILOGE("BluetoothHostProxy::EnableBle WriteInterfaceToken error");

return false;

}

MessageParcel reply;

MessageOption option = {MessageOption::TF\_SYNC};

int32\_t error = InnerTransact(IBluetoothHost::Code::BT\_ENABLE\_BLE, option, data, reply);

if (error != NO\_ERROR) {

HILOGE("BluetoothHostProxy::EnableBle done fail, error: %{public}d", error);

return false;

}

return reply.ReadBool();

}

​ Proxy端发送的消息ID为BT_ENABLE_BLE,并封装为消息序列MessageParcel对象。

​ BluetoothHostStub的OnRemoteRequest将会收到code为9即携带BT_ENABLE_BLE的消息序列,并在BluetoothHostStub中解析处理,如下:


int32\_t BluetoothHostStub::OnRemoteRequest(

uint32\_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)

{

HILOGD("BluetoothHostStub::OnRemoteRequest, cmd = %{public}d, flags= %{public}d", code, option.GetFlags());

std::u16string descriptor = BluetoothHostStub::GetDescriptor();

std::u16string remoteDescriptor = data.ReadInterfaceToken();

if (descriptor != remoteDescriptor) {

HILOGE("BluetoothHostStub::OnRemoteRequest, local descriptor is not equal to remote");

return ERR\_INVALID\_STATE;

}

auto itFunc = memberFuncMap\_.find(code);

if (itFunc != memberFuncMap\_.end()) {

auto memberFunc = itFunc-\>second;

if (memberFunc != nullptr) {

return memberFunc(this, data, reply);

}

}

HILOGW("BluetoothHostStub::OnRemoteRequest, default case, need check.");

return IPCObjectStub::OnRemoteRequest(code, data, reply, option);

}

​ 对应的映射关系如下:


const std::map\<uint32\_t, std::function\<ErrCode(BluetoothHostStub \*, MessageParcel &, MessageParcel &)\>\>

BluetoothHostStub::memberFuncMap\_ = {

...

{BluetoothHostStub::BT\_ENABLE\_BLE,

std::bind(&BluetoothHostStub::EnableBleInner, std::placeholders::\_1, std::placeholders::\_2,

std::placeholders::\_3)},

​ 即将在EnableBleInner函数中向下调用:


ErrCode BluetoothHostStub::EnableBleInner(MessageParcel &data, MessageParcel &reply)

{

bool result = EnableBle();

bool ret = reply.WriteBool(result);

if (!ret) {

HILOGE("BluetoothHostStub: reply writing failed in: %{public}s.", \_\_func\_\_);

return TRANSACTION\_ERR;

}

return NO\_ERROR;

}

​ 其中EnableBle()函数的实现是在BluetoothHostServer中,此时已经从ipc目录执行到了server目录,如下:


bool BluetoothHostServer::EnableBle()

{

HILOGD("[%{public}s]: %{public}s(): Enter!", \_\_FILE\_\_, \_\_FUNCTION\_\_);

return IAdapterManager::GetInstance()-\>Enable(BTTransport::ADAPTER\_BLE);

}

​ AdapterManager是IAdapterManager的实现类,AdapterManager中的Enable方法如下,其中传入的参数为BTTransport::ADAPTER_BLE。此时,已经通过server目录进入到了service核心目录。


bool AdapterManager::Enable(const BTTransport transport) const

{

LOG\_DEBUG("%{public}s start transport is %{public}d", \_\_PRETTY\_FUNCTION\_\_, transport);

std::lock\_guard\<std::recursive\_mutex\> lock(pimpl-\>syncMutex\_);

if (PermissionUtils::VerifyDiscoverBluetoothPermission() == PERMISSION\_DENIED) {

LOG\_ERROR("Enable() false, check permission failed");

return false;

}

if (GetSysState() != SYS\_STATE\_STARTED) {

LOG\_ERROR("AdapterManager system is stoped");

return false;

}

if (pimpl-\>adapters\_[transport] == nullptr) {

LOG\_INFO("%{public}s BTTransport not register", \_\_PRETTY\_FUNCTION\_\_);

return false;

}

if (GetState(transport) == BTStateID::STATE\_TURN\_OFF) {

utility::Message msg(AdapterStateMachine::MSG\_USER\_ENABLE\_REQ);

pimpl-\>dispatcher\_-\>PostTask(std::bind(&AdapterManager::impl::ProcessMessage, pimpl.get(), transport, msg));

return true;

} else if (GetState(transport) == BTStateID::STATE\_TURN\_ON) {

LOG\_INFO("%{public}s is turn on", \_\_PRETTY\_FUNCTION\_\_);

return false;

} else {

LOG\_INFO("%{public}s is turning state %{public}d", \_\_PRETTY\_FUNCTION\_\_, GetState(transport));

return false;

}

}

​ 此时蓝牙为关闭状态,即BTStateID::STATE_TURN_OF,因此进入子线程的ProcessMessage函数中处理。其中传入的参数msg封装了AdapterStateMachine::MSG_USER_ENABLE_REQ消息。其中AdapterStateMachine是继承了StateMachine的状态机。


void AdapterManager::impl::ProcessMessage(const BTTransport transport, const utility::Message &msg)

{

std::lock\_guard\<std::recursive\_mutex\> lock(syncMutex\_);

if (adapters\_[transport] == nullptr) {

LOG\_DEBUG("%{public}s adapter is nullptr", \_\_PRETTY\_FUNCTION\_\_);

return;

}

if (adapters\_[transport]-\>stateMachine\_ == nullptr) {

LOG\_DEBUG("%{public}s stateMachine\_ is nullptr", \_\_PRETTY\_FUNCTION\_\_);

return;

}

adapters\_[transport]-\>stateMachine\_-\>ProcessMessage(msg);

}

​ AdapterStateMachine状态机里面的ProcessMessage函数没有重写处理,会进入StateMachine的默认ProcessMessage函数进行分发。AdapterState继承了utility::StateMachine::State,AdapterState的子类将对AdapterStateMachine::MSG_USER_ENABLE_REQ消息处理。AdapterStateMachine状态机的初始化状态为TURN_OFF_STATE,也是当前的状态,最终在AdapterState的子类AdapterTurnOffState中分发AdapterStateMachine::MSG_USER_ENABLE_REQ消息。

​ AdapterTurnOffState的Dispatch方法处理如下:


bool AdapterTurnOffState::Dispatch(const utility::Message &msg)

{

switch (msg.what\_) {

case AdapterStateMachine::MSG\_USER\_ENABLE\_REQ:

Transition(TURNING\_ON\_STATE);

return true;

default:

return false;

}

}

​ AdapterTurnOffState对AdapterStateMachine::MSG_USER_ENABLE_REQ消息的处理就是将当前状态从TURN_OFF_STATE状态变为TURNING_ON_STATE状态,因此状态机自动进入AdapterTurningOnState状态的Entry()函数。如下:


void AdapterTurningOnState::Entry()

{

BTTransport transport =

(adapter\_.GetContext()-\>Name() == ADAPTER\_NAME\_CLASSIC) ? BTTransport::ADAPTER\_BREDR : BTTransport::ADAPTER\_BLE;

AdapterManager::GetInstance()-\>OnAdapterStateChange(transport, BTStateID::STATE\_TURNING\_ON);

LOG\_DEBUG("AdapterStateMachine::Timer enable adapter start transport is %{public}d", transport);

adapterTimer\_-\>Start(ENABLE\_DISABLE\_TIMEOUT\_TIME, false);

adapter\_.GetContext()-\>Enable();

}

​ IAdapterBle和IAdapterClassic都是IAdapter的子类,当前adapter_对象是IAdapterBle的子类BleAdapter对象,因此进入BleAdapter的Enable()方法:


void BleAdapter::Enable()

{

LOG\_DEBUG("[BleAdapter] %{public}s:%{public}s", \_\_func\_\_, Name().c\_str());

GetDispatcher()-\>PostTask(std::bind(&BleAdapter::EnableTask, this));

}

​ 此时进入任务线程中执行EnableTask方法,如下:


bool BleAdapter::EnableTask()

{

LOG\_DEBUG("[BleAdapter] %{public}s", \_\_func\_\_);

std::lock\_guard\<std::recursive\_mutex\> lk(pimpl-\>syncMutex\_);

bool ret = (BTM\_Enable(LE\_CONTROLLER) == BT\_NO\_ERROR);

if (!ret) {

pimpl-\>btmEnableFlag\_ = false;

LOG\_ERROR("[BleAdapter] %{public}s:BTM enable failed!", \_\_func\_\_);

} else {

pimpl-\>btmEnableFlag\_ = true;

LoadConfig();

ret = (InitBtmAndGap() == BT\_NO\_ERROR);

LOG\_DEBUG("[BleAdapter] %{public}s:BTM enable successfully!", \_\_func\_\_);

}

GetContext()-\>OnEnable(ADAPTER\_NAME\_BLE, ret);

return ret;

}

​ 其中GetContext()->OnEnable(ADAPTER_NAME_BLE, ret)方法是对最终是否打开低功耗蓝牙开关的一个回调触发。而BTM_Enable方法是在stack目录下的btm.c文件中实现,将继续实现打开低功耗蓝牙操作。此时已经从service目录进入到stack目录了。


int BTM\_Enable(int controller)

{

LOG\_DEBUG("%{public}s start", \_\_FUNCTION\_\_);

if (controller != BREDR\_CONTROLLER && controller != LE\_CONTROLLER) {

return BT\_BAD\_PARAM;

}

if (!IS\_INITIALIZED()) {

return BT\_BAD\_STATUS;

}

int result = BT\_NO\_ERROR;

MutexLock(g\_modeLock);

if (controller == BREDR\_CONTROLLER) {

if (g\_currentMode == MODE\_NONE) {

result = BtmEnableBrEdrAndSharedModules();

} else if (g\_currentMode == MODE\_LE) {

result = BtmEnableBrEdrModules();

}

if (result == BT\_NO\_ERROR) {

g\_currentMode |= MODE\_BREDR;

}

} else if (controller == LE\_CONTROLLER) {

if (g\_currentMode == MODE\_NONE) {

result = BtmEnableLeAndSharedModules();

} else if (g\_currentMode == MODE\_BREDR) {

result = BtmEnableLeModules();

}

if (result == BT\_NO\_ERROR) {

g\_currentMode |= MODE\_LE;

}

}

#ifdef DEBUG

BtmOutputCurrentStatus();

#endif

MutexUnlock(g\_modeLock);

LOG\_DEBUG("%{public}s end", \_\_FUNCTION\_\_);

return result;

}

​ btm.c的流程相对繁琐,后面3.3节用时序图介绍。

3.2 流程时序图

​ 上面3.1对应的时序流程,如下:

​ 1. napi调用host中的EnableBle()开始,最后在proxy中调用SendRequest,触发stub中的OnRemoteRequest()。

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

​ 2. Bluetooth_host_stub->i_bluetooth_host:stub中的OnRemoteRequest()会调用server中的EnableBle()的实现。

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

  1. bluetooth_host_server->state_machine:server调用adapter_manager的实现部分,最终调用状态机的transition()。

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

  1. state_machine->btm:adapter_state_machine通过调用ble_adapter的Enable()来实现对btm中的BTM_enable()的调用。

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

3.3 stack目录下btm使能时序图

​ btm.c的BTM_Enable方法的详细过程,请参考如下的流程图:

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

​ 启动ble的所有modules;初始化HCI接口前,首先调用libbluetooth_hal.z.so,初始化提供的接口函数。

​ 之后,初始化HCI:创建相关list,如Failure,Cmd,Event,Acl;初始化hci发送、接收队列;初始化hciHal,HciInitHal信号量。如下:

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

​ BtmController的初始化,startAcl,startLeSecurity,startWhiteList。

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

​ 启动whitelist的详细步如下:

#夏日挑战赛#初识OpenHarmony蓝牙模块-鸿蒙开发者社区

​ whitelist启动后,再启动所有的btm modules,则BTM_Enable完成。

4. 蓝牙接口说明

​ 当前提供了基本的蓝牙连接和profile 功能,LTS3.0.1仅包括A2DP, BLE, GATT, SPP等基本接口。其他的功能将会在后续版本中完善和提供。

| 接口文件 | 功能 | 说明 |

| ------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |

| bluetooth_a2dp_src.h | interface and callback function of a2dp source | A2DP,负责传输音频的profile,手机和蓝牙耳机建立连接后传输音频就是通过A2DP |

| bluetooth_ble_advertiser.h | Defines advertiser, including avertise data and callbacks, and advertiser functions | BLE 中心设备、外围设备相关回调,功能 |

| bluetooth_ble_central_manager.h | Central manager common functions | |

| bluetooth_def.h | Defined here are various status codes | bluetooth中的业务常量定义及枚举定义 |

| bluetooth_device_class.h | Bluetooth device class | BluetoothDeviceClass的API接口类 |

| bluetooth_device.h | Bluetooth device major class | bluetooth device major class的static常量定义 |

| bluetooth_gatt_characteristic.h | Bluetooth gatt characteristic interface. | Gatt 相关的接口文件 |

| bluetooth_gatt_client.h | Bluetooth gatt client interface | |

| bluetooth_gatt_descriptor.h | Bluetooth gatt descriptor interface | |

| bluetooth_gatt_manager.h | gatt manager interface | |

| bluetooth_gatt_server.h | gatt server interface | |

| bluetooth_gatt_service.h | gatt service interface | |

| bluetooth_host.h | bluetooth host, including observer and common functions | host本机管理相关接口,如enable |

| bluetooth_remote_device.h | Bluetooth Remote Device API | 远端设备的API接口 |

| bluetooth_socket.h | spp client socket functions | socket,串口相关功能 |

| bluetooth_socket_inputstream.h | spp inputstream framework functions, including basic functions | |

| bluetooth_socket_outputstream.h | spp outputstream framework functions, including basic functions | |

| bluetooth_types.h | macro definition | bluetooth中模板相关的宏定义 |

| uuid.h | framework uuid interface. | uuid类,提供uuid相关接口功能。如字符串和uuid之间的相互转化 |

5. 蓝牙部分业务应用场景

​ LTS3.0.1蓝牙部分目前仅提供c/c++应用开发的接口,由于底层的驱动程序尚待完善,目前提供的只有BLE相关的接口,包括BLE设备gatt相关的操作,以及BLE广播、扫描等功能,其它A2DP,AVRCP,HFP等相关接口在后续增量发布。

5.1 Host管理

​ 蓝牙host管理主要是针对蓝牙本机的基本操作,包括打开和关闭蓝牙(包括传统蓝牙和BLE),设置和获取本机蓝牙名称,传统蓝牙的扫描和取消扫描周边蓝牙设备、获取本机蓝牙profile service列表,获取对其他设备的连接状态,获取、移除本机蓝牙(包括传统蓝牙和BLE)已配对的蓝牙设备或列表等。

​ 主要接口如下表:

| 接口名 | 功能描述 |

| ------------------------------------------------------------ | ------------------------------------------------------------ |

| GetDefaultHost(); | 获取BluetoothHost实例,去管理本机蓝牙操作。 |

| EnableBt(); | 打开本机蓝牙。 |

| DisableBt(); | 关闭本机蓝牙。 |

| GetBtState() const; | 获取本机传统蓝牙状态: <br />* BTStateID::STATE_TURNING_ON; <br />* BTStateID::STATE_TURN_ON; <br />* BTStateID::STATE_TURNING_OFF; <br />* BTStateID::STATE_TURN_OFF. |

| SetLocalName(const std::string &name); | 设置本机蓝牙名称。 |

| GetLocalName() | 获取本机蓝牙名称。 |

| int GetBtConnectionState() const; | bluetooth connects state. <br /> * BTConnectState::CONNECTING; <br /> * BTConnectState::CONNECTED; <br /> * BTConnectState::DISCONNECTING; <br /> * BTConnectState::DISCONNECTED. |

| startBtDiscovery() | 发起蓝牙设备扫描。 |

| cancelBtDiscovery() | 取消蓝牙设备扫描。 |

| isBtDiscovering() | 检查蓝牙是否在扫描设备中。 |

| std::vector<uint32_t> GetProfileList() | 获取 profile service ID 列表 |

| GetBtProfileConnState(uint32_t profileId) | 获取本机蓝牙profile对其他设备的连接状态。BTConnectState |

| getPairedDevices(int transport) | 获取本机蓝牙已配对的蓝牙设备列。 |

| bool BluetoothFactoryReset(); | Factory reset bluetooth service |

| GetLocalDeviceClass() const; | 获取本机device class |

| SetLocalDeviceClass(const BluetoothDeviceClass &deviceClass); | 设置本机device class |

| DisableBle(); | 关闭本机BLE |

| EnableBle(); | 打开本机ble |

| IsBleEnabled() const; | 获取ble状态 |

5.1.1 打开/关闭传统蓝牙

​ 主要步骤:

​ 1. 调用BluetoothHost的GetDefaultHost()接口,获取BluetoothHost实例,管理host蓝牙操作;

​ 2. 打开蓝牙;

​ 3. 查蓝牙状态,关闭蓝牙。

5.1.2 本机传统蓝牙扫描

​ 主要步骤:

​ 1. 调用BluetoothHost的GetDefaultHost()接口,获取BluetoothHost实例,管理host蓝牙操作;

​ 2. 打开蓝牙;

​ 3. 开始扫描;

​ 4. 验证扫描状态,最后关闭蓝牙。

5.2 BLE扫描/广播

​ OpenHarmony低功耗蓝牙的BLE设备交互时,会分为不同的角色,即中心设备和外围设备。其中,中心设备负责扫描外围设备,发现广播信息;而外围设备负责发送广播信息。

​ 主要功能是BLE广播和扫描。根据指定状态获取外围设备;启动或停止BLE扫描、广播。

5.2.1 BLE广播

​ 主要步骤:

​ 1. 进行BLE广播前需要先继承*Bluetooth::BleAdvertiseCallback*类实现OnStartResultEvent(int result)回调,用于获取广播结果;

​ 2. 获取广播对象,构造广播参数和广播数据;

​ 3. 调用StartAdvertising(const BleAdvertiserSettings &settings, const BleAdvertiserData &advData,

​ const BleAdvertiserData &scanResponse, BleAdvertiseCallback &callback)接口开始BLE广播。

5.2.2 BLE扫描

​ 主要步骤:

​ 1. 进行BLE扫描之前先要继承BleCentralManagerCallback类实现scanResultEvent和scanFailedEvent回调函数,用于接收扫描结果;

​ 2. 调用BleCentralManager(BleCentralManagerCallback &callback)构造函数,获取中心设备管理对象;

​ 3. 构造扫描过滤器(或不使用过滤器扫描);

​ 4. 调用startScan()/StartScan(const BleScanSettings &settings)开始扫描BLE设备,在回调中获取扫描到的BLE设备

5.3 GATT 服务端、客户端

​ BLE外围设备和中心设备建立GATT连接,通过该连接中心设备可以获取外围设备所支持的Service、Characteristic、Descriptor等数据。

同时,中心设备可以向外围设备进行数据请求,并向外围设备写入Characteristic、Descriptor等特征值数据。

​ 两台设备建立连接后,其中一台作为GATT服务端,另一台作为GATT客户端。通常发送广播的外围设备作为服务端,负责扫描的中心设备作为客户端。

5.3.1 GATT服务端

​ BLE外围设备作为服务端,可以接收来自中心设备(客户端)的GATT连接请求,应答来自中心设备的特征值内容读取和写入请求,并向中心设备提供数据,从而实现信息交互和消息同步。同时外围设备还可以主动向中心设备发送数据。

​ 主要步骤:

​ 1. 和BLE类似,要想正常调用相关的接口调用,首先得实现GattServerCallback的中的相关的回调函数接口

​ 2. 调用接口创建外围设备服务端并开启服务。

​ 3. 调用*GattService(UUID uuid, boolean isPrimary)*接口创建服务对象,向外围设备添加服务。

​ 4. 从回调接口*OnCharacteristicWriteRequest*中获取中心设备发送来的消息,调用*NotifyCharacteristicChanged*接口向中心设备发送通知。

5.3.2 GATT客户端

​ BLE外围设备和中心设备建立GATT连接,通过该连接,中心设备可以获取外围设备所支持的Service、Characteristic、Descriptor等数据。另外,中心设备也可以向外围设备进行数据请求,并向外围设备写入Characteristic、Descriptor等特征值数据。

​ 主要步骤:

​ 1. 调相关接口启动BLE扫描来获取外围设备(可参考BLE扫描部分);

​ 2. 获取外围设备后,初始化GattClient对象;

​ 3. 调用Connect(GattClientCallback &callback, bool isAutoConnect, int transport)接口,建立与外围BLE设备的GATT连接,boolean参数isAutoConnect用于设置是否允许设备在可发现距离内自动建立GATT连接。

​ 4. 启动GATT连接后,会触发OnConnectionStateChanged(int connectionState, int ret)回调,根据回调结果判断是否连接GATT成功。

​ 5. 在GATT连接成功时,中心设备可以调用DiscoverServices()接口,获取外围设备支持的Services、Characteristics等特征值,在回调OnServicesDiscovered(int status)中获取外围设备支持的服务和特征值,并根据UUID判断是什么服务。

​ 6. 根据获取到的服务和特征值,调用read和write方法可以读取或者写入对应特征值数据。

5.4 SPP

​ OpenHarmony蓝牙 SPP分为服务端和客户端程序。蓝牙串行端口基于SPP协议(Serial Port Profile),能在蓝牙设备之间创建串口进行数据传输,手机一般以客户端的角色主动连接SPP协议设备。主要类对象有:SppClientSocket、SppServerSocket以及SocketFactory。

5.4.1 服务端

​ 程序步骤:

​ 1. 首先打开蓝牙;

​ 2. 创建SPP服务端对象指针,创建对象,并且打开监听状态

​ 3. Accept一定条件的客户端的请求

​ 4. 满足某些条件,关闭客户端程序

5.4.2 客户端

​ 程序步骤:

​ 1. 打开蓝牙;

​ 2. 创建SppClientSocket对象(或指针);

​ 3. 连接server,connect();

​ 4. 断开连接,close()

更多原创内容请关注:深开鸿技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建OpenHarmony生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2023-1-12 11:13:11修改
3
收藏 4
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

感谢老师对蓝牙部分详细的讲解。

回复
2022-7-5 14:06:06
回复
    相关推荐