mirror of
https://github.com/openharmony/drivers_peripheral.git
synced 2026-08-24 18:15:56 -04:00
@@ -0,0 +1,67 @@
|
||||
# NearLink<a name="ZH-CN_TOPIC_0000001148577119"></a>
|
||||
|
||||
- [Introduction](#section11660541593)
|
||||
- [Directory Structure](#section161941989596)
|
||||
- [Constraints](#section119744591305)
|
||||
- [Usage](#section1312121216216)
|
||||
- [DLI APIs](#section129654513264)
|
||||
|
||||
- [Repositories Involved](#section1371113476307)
|
||||
|
||||
## Introduction<a name="section11660541593"></a>
|
||||
|
||||
The NearLink driver module provides APIs for accessing and using the NearLink short-range communication protocol, including DLI initialization, data sending and receiving, and closing the NearLink DLI.
|
||||
|
||||
## Directory Structure<a name="section161941989596"></a>
|
||||
|
||||
```
|
||||
/foundation/drivers/peripheral/nearlink
|
||||
├── bundle.json # Component description and dependency configuration
|
||||
├── drivers_peripheral_nearlink.gni # Build feature parameter configuration
|
||||
├── dli # DLI module
|
||||
│ └── test # DLI test cases
|
||||
└── LICENSE # Copyright statement
|
||||
└── bundle.json # Component description file
|
||||
```
|
||||
|
||||
## Constraints<a name="section119744591305"></a>
|
||||
|
||||
The NearLink driver module is written in C++ and based on the DLI framework. It supports the standard system only.
|
||||
|
||||
## Usage<a name="section1312121216216"></a>
|
||||
|
||||
NearLink DLI APIs are provided. The DLI APIs include initialization, sending and receiving DLI packets, and close.
|
||||
|
||||
### DLI APIs<a name="section129654513264"></a>
|
||||
|
||||
- Initialize the NearLink HAL:
|
||||
|
||||
```
|
||||
/* Initialize the NearLink HAL and register the callback. */
|
||||
int32_t SleHalInit(const sptr<ISleHciCallback>& callbackObj);
|
||||
```
|
||||
|
||||
- Send a packet:
|
||||
|
||||
```
|
||||
/* Send a packet to the chip. */
|
||||
int32_t SleSendHciPacket(const std::vector<uint8_t>& data);
|
||||
```
|
||||
|
||||
- Receive a packet:
|
||||
|
||||
```
|
||||
/* Receive a packet from the chip. */
|
||||
int32_t hciPacketReceived(uint32_t type, const std::vector<uint8_t> &data);
|
||||
```
|
||||
|
||||
- Close the NearLink DLI:
|
||||
|
||||
```
|
||||
/* Close the NearLink DLI and release resources. */
|
||||
int32_t Close();
|
||||
```
|
||||
|
||||
## Repositories Involved<a name="section1371113476307"></a>
|
||||
|
||||
drivers\_peripheral\_nearlink
|
||||
@@ -0,0 +1,69 @@
|
||||
# 星闪组件<a name="ZH-CN_TOPIC_0000001148577119"></a>
|
||||
|
||||
- [简介](#section11660541593)
|
||||
- [目录](#section161941989596)
|
||||
- [约束](#section119744591305)
|
||||
- [说明](#section1312121216216)
|
||||
- [DLI接口使用说明](#section129654513264)
|
||||
|
||||
- [相关仓](#section1371113476307)
|
||||
|
||||
## 简介<a name="section11660541593"></a>
|
||||
|
||||
星闪(NearLink)驱动组件为设备提供接入与使用星闪短距通信协议的相关接口,包括DLI初始化,数据收发以及关闭星闪DLI等。
|
||||
|
||||
## 目录<a name="section161941989596"></a>
|
||||
|
||||
```
|
||||
/foundation/drivers/peripheral/nearlink
|
||||
├── bundle.json # 组件描述及依赖配置
|
||||
├── drivers_peripheral_nearlink.gni # 编译特性参数配置
|
||||
├── dli # DLI模块
|
||||
│ └── test # DLI测试用例
|
||||
└── LICENSE # 版权声明文件
|
||||
└── bundle.json # 部件描述文件
|
||||
```
|
||||
|
||||
## 约束<a name="section119744591305"></a>
|
||||
|
||||
星闪驱动组件使用C++语言编写,基于DLI框架,仅支持标准系统。
|
||||
|
||||
## 说明<a name="section1312121216216"></a>
|
||||
|
||||
目前提供星闪DLI接口,DLI接口包括初始化、发送接收DLI数据包、关闭等功能。
|
||||
|
||||
|
||||
### DLI接口使用说明<a name="section129654513264"></a>
|
||||
|
||||
- 初始化星闪HAL:
|
||||
|
||||
```
|
||||
/* 初始化星闪HAL,注册回调 */
|
||||
int32_t SleHalInit(const sptr<ISleHciCallback>& callbackObj);
|
||||
```
|
||||
|
||||
- 发送数据包:
|
||||
|
||||
```
|
||||
/* 向芯片发送数据包 */
|
||||
int32_t SleSendHciPacket(const std::vector<uint8_t>& data);
|
||||
```
|
||||
|
||||
- 接收数据包:
|
||||
|
||||
```
|
||||
/* 接收来自芯片的数据包 */
|
||||
int32_t hciPacketReceived(uint32_t type, const std::vector<uint8_t> &data);
|
||||
```
|
||||
|
||||
|
||||
- 关闭星闪DLI:
|
||||
|
||||
```
|
||||
/* 关闭星闪DLI,释放资源 */
|
||||
int32_t Close();
|
||||
```
|
||||
|
||||
## 相关仓<a name="section1371113476307"></a>
|
||||
|
||||
drivers\_peripheral\_nearlink
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@ohos/drivers_peripheral_nearlink",
|
||||
"description": "nearlink device driver",
|
||||
"version": "4.1",
|
||||
"license": "Apache License 2.0",
|
||||
"publishAs": "code-segment",
|
||||
"segment": {
|
||||
"destPath": "drivers/peripheral/nearlink"
|
||||
},
|
||||
"dirs": {},
|
||||
"scripts": {},
|
||||
"component": {
|
||||
"name": "drivers_peripheral_nearlink",
|
||||
"subsystem": "hdf",
|
||||
"features": [
|
||||
"drivers_peripheral_nearlink_feature_support_send_disable_hci",
|
||||
"drivers_peripheral_nearlink_reload_address"
|
||||
],
|
||||
"adapted_system_type": ["standard"],
|
||||
"rom": "",
|
||||
"ram": "",
|
||||
"deps": {
|
||||
"components": [
|
||||
"c_utils",
|
||||
"hdf_core",
|
||||
"hilog",
|
||||
"drivers_interface_nearlink",
|
||||
"samgr",
|
||||
"ipc",
|
||||
"ffrt",
|
||||
"bounds_checking_function",
|
||||
"init"
|
||||
],
|
||||
"third_party": [
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
"sub_component": [
|
||||
"//drivers/peripheral/nearlink/dli:nearlink_entry",
|
||||
"//drivers/peripheral/nearlink/off_find:off_find_entry"
|
||||
],
|
||||
"test": [
|
||||
"//drivers/peripheral/nearlink/dli/test:nearlink_hdi_test"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if (defined(ohos_lite)) {
|
||||
group("nearlink_entry") {
|
||||
deps = []
|
||||
}
|
||||
} else {
|
||||
group("nearlink_entry") {
|
||||
deps = [ "dli_service:hdf_nearlink_service" ]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
# Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import("//build/config/components/hdi/hdi.gni")
|
||||
import("../../drivers_peripheral_nearlink.gni")
|
||||
|
||||
|
||||
ohos_shared_library("libsle_hci_interface_service_1.1") {
|
||||
sanitize = {
|
||||
cfi = true # Enable/disable control flow integrity detection
|
||||
boundary_sanitize = true # Enable boundary san detection
|
||||
cfi_cross_dso = true # Cross-SO CFI Checks
|
||||
integer_overflow = true # Enable integer overflow detection
|
||||
ubsan = true # Enable some Ubsan options
|
||||
debug = false
|
||||
}
|
||||
branch_protector_ret = "pac_ret"
|
||||
|
||||
cflags = [
|
||||
"-Os",
|
||||
"-fdata-sections",
|
||||
"-ffunction-sections",
|
||||
"-fno-unwind-tables",
|
||||
"-fno-asynchronous-unwind-tables",
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
"-fPIC",
|
||||
"-fno-common",
|
||||
"-fstack-protector-strong",
|
||||
"-fvisibility-inlines-hidden",
|
||||
"-flto",
|
||||
]
|
||||
cflags_cc = cflags
|
||||
ldflags = [
|
||||
"-Wl,--as-needed",
|
||||
"-Wl,--gc-sections",
|
||||
"-Wl,--no-whole-archive",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
".",
|
||||
"implement",
|
||||
]
|
||||
|
||||
sources = [
|
||||
"sle_hci_interface_impl.cpp",
|
||||
"implement/sle_address.cpp",
|
||||
"implement/h4_protocol.cpp",
|
||||
"implement/dli_protocol.cpp",
|
||||
"implement/dli_watcher.cpp",
|
||||
"implement/vendor_interface.cpp",
|
||||
"implement/thread_util.cpp",
|
||||
]
|
||||
|
||||
defines = []
|
||||
|
||||
if (drivers_peripheral_nearlink_reload_address) {
|
||||
defines += [ "RELOAD_ADDRESS" ]
|
||||
}
|
||||
|
||||
if (is_standard_system) {
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"drivers_interface_nearlink:nearlink_hci_idl_headers",
|
||||
"hdf_core:libhdf_host",
|
||||
"hdf_core:libhdf_utils",
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_core",
|
||||
"ffrt:libffrt",
|
||||
]
|
||||
} else {
|
||||
external_deps = [
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_core",
|
||||
]
|
||||
}
|
||||
|
||||
external_deps += [ "init:libbegetutil" ]
|
||||
install_images = [ chipset_base_dir ]
|
||||
subsystem_name = "hdf"
|
||||
part_name = "drivers_peripheral_nearlink"
|
||||
}
|
||||
|
||||
ohos_shared_library("libnearlink_hci_hdi_driver") {
|
||||
sanitize = {
|
||||
cfi = true # Enable/disable control flow integrity detection
|
||||
boundary_sanitize = true # Enable boundary san detection
|
||||
cfi_cross_dso = true # Cross-SO CFI Checks
|
||||
integer_overflow = true # Enable integer overflow detection
|
||||
ubsan = true # Enable some Ubsan options
|
||||
debug = false
|
||||
}
|
||||
branch_protector_ret = "pac_ret"
|
||||
|
||||
cflags = [
|
||||
"-Os",
|
||||
"-fdata-sections",
|
||||
"-ffunction-sections",
|
||||
"-fno-unwind-tables",
|
||||
"-fno-asynchronous-unwind-tables",
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
"-fPIC",
|
||||
"-fno-common",
|
||||
"-fstack-protector-strong",
|
||||
"-fvisibility-inlines-hidden",
|
||||
"-flto",
|
||||
]
|
||||
cflags_cc = cflags
|
||||
ldflags = [
|
||||
"-Wl,--as-needed",
|
||||
"-Wl,--gc-sections",
|
||||
"-Wl,--no-whole-archive",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
".",
|
||||
]
|
||||
|
||||
sources = [ "sle_dli_interface_driver.cpp" ]
|
||||
|
||||
if (is_standard_system) {
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"hdf_core:libhdf_host",
|
||||
"hdf_core:libhdf_ipc_adapter",
|
||||
"hdf_core:libhdf_utils",
|
||||
"hdf_core:libhdi",
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_single",
|
||||
]
|
||||
} else {
|
||||
external_deps = [
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_single",
|
||||
]
|
||||
}
|
||||
|
||||
external_deps += [
|
||||
"drivers_interface_nearlink:libnearlink_hci_stub_1.0",
|
||||
"drivers_interface_nearlink:libnearlink_hci_stub_1.1",
|
||||
]
|
||||
|
||||
shlib_type = "hdi"
|
||||
install_images = [ chipset_base_dir ]
|
||||
subsystem_name = "hdf"
|
||||
part_name = "drivers_peripheral_nearlink"
|
||||
}
|
||||
|
||||
group("hdf_nearlink_service") {
|
||||
deps = [
|
||||
":libnearlink_hci_hdi_driver",
|
||||
":libsle_hci_interface_service_1.1",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_DLI_INTERNAL_H
|
||||
#define OHOS_HDI_NEARLINK_DLI_INTERNAL_H
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
typedef enum {
|
||||
DLI_PACKET_TYPE_UNKNOWN = 0,
|
||||
DLI_PACKET_TYPE_SLE_CMD = 0xA1,
|
||||
DLI_PACKET_TYPE_SLE_EVENT = 0xA2,
|
||||
DLI_PACKET_TYPE_SLE_ACB_DATA = 0xA3,
|
||||
DLI_PACKET_TYPE_SLE_ICB_DATA = 0xA4,
|
||||
DLI_PACKET_TYPE_MAX,
|
||||
} DliPacketType;
|
||||
|
||||
struct PacketHeader {
|
||||
uint8_t headerSize;
|
||||
uint8_t dataLengthOffset;
|
||||
uint8_t dataLengthSize;
|
||||
};
|
||||
|
||||
// opcode (DLI_SLE_Cmd_Complete_Evt opcode)
|
||||
const uint16_t SLE_DLI_COMMAND_COMPLETE_EVENT = 0x0002;
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_NEARLINK_DLI_INTERNAL_H */
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include "nearlink_hdf_log.h"
|
||||
#include "dli_protocol.h"
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
const PacketHeader DliProtocol::header_[DLI_PACKET_TYPE_MAX] = {
|
||||
{.headerSize = 0, .dataLengthOffset = 0, .dataLengthSize = 0}, /* 0 */
|
||||
{.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 1 */
|
||||
{.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 2 */
|
||||
{.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 3 */
|
||||
{.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 4 */
|
||||
};
|
||||
|
||||
const PacketHeader &DliProtocol::GetPacketHeaderInfo(DliPacketType packetType)
|
||||
{
|
||||
if (packetType >= DLI_PACKET_TYPE_MAX) {
|
||||
return header_[DLI_PACKET_TYPE_UNKNOWN];
|
||||
}
|
||||
return header_[DliProtocol::TypeConvert(packetType)];
|
||||
}
|
||||
|
||||
ssize_t DliProtocol::Read(int fd, uint8_t *data, size_t length)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
char buf[bufsize] = {0};
|
||||
ssize_t ret = TEMP_FAILURE_RETRY(read(fd, data, length));
|
||||
if (ret == -1) {
|
||||
strerror_r(errno, buf, sizeof(buf));
|
||||
HDF_LOGE("read failed");
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t DliProtocol::Write(int fd, const uint8_t *data, size_t length)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
char buf[bufsize] = {0};
|
||||
ssize_t ret = 0;
|
||||
do {
|
||||
ret = TEMP_FAILURE_RETRY(write(fd, data, length));
|
||||
} while (ret == -1 && errno == EAGAIN);
|
||||
|
||||
if (ret == -1) {
|
||||
strerror_r(errno, buf, sizeof(buf));
|
||||
HDF_LOGE("write failed");
|
||||
} else if (static_cast<size_t>(ret) != length) {
|
||||
HDF_LOGE("write data %{public}zd less than %{public}zu.", ret, length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t DliProtocol::TypeConvert(DliPacketType packetType)
|
||||
{
|
||||
switch (packetType) {
|
||||
case DLI_PACKET_TYPE_SLE_EVENT:
|
||||
return static_cast<uint8_t>(DLI_PACKET_TYPE_SLE_EVENT) & 0x0F;
|
||||
default:
|
||||
HDF_LOGE("type convert error.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_DLI_PROTOCOL_H
|
||||
#define OHOS_HDI_NEARLINK_DLI_PROTOCOL_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
#include <functional>
|
||||
#include "dli_internal.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
class DliProtocol {
|
||||
public:
|
||||
using DliDataCallback = std::function<void(const std::vector<uint8_t> &data)>;
|
||||
|
||||
DliProtocol() = default;
|
||||
virtual ~DliProtocol() = default;
|
||||
|
||||
virtual ssize_t SendPacket(const std::vector<uint8_t> &packetData) = 0;
|
||||
|
||||
const PacketHeader& GetPacketHeaderInfo(DliPacketType packetType);
|
||||
|
||||
protected:
|
||||
static ssize_t Read(int fd, uint8_t *data, size_t length);
|
||||
static ssize_t Write(int fd, const uint8_t *data, size_t length);
|
||||
static uint8_t TypeConvert(DliPacketType packetType);
|
||||
static const PacketHeader header_[DLI_PACKET_TYPE_MAX];
|
||||
};
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_NEARLINK_DLI_PROTOCOL_H */
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/syscall.h>
|
||||
#include "nearlink_hdf_log.h"
|
||||
#include "sle_hal_constant.h"
|
||||
#include "dli_watcher.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
DliWatcher::DliWatcher()
|
||||
{}
|
||||
|
||||
DliWatcher::~DliWatcher()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool DliWatcher::AddFdToWatcher(int fd, DliDataCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fdsMutex_);
|
||||
fds_[fd] = callback;
|
||||
ThreadWakeup();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DliWatcher::RemoveFdToWatcher(int fd)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fdsMutex_);
|
||||
fds_.erase(fd);
|
||||
ThreadWakeup();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DliWatcher::SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback)
|
||||
{
|
||||
std::chrono::seconds seconds = std::chrono::duration_cast<std::chrono::seconds>(timeout);
|
||||
std::lock_guard<std::mutex> lock(timeoutMutex_);
|
||||
timeoutTimer_.tv_sec = seconds.count();
|
||||
timeoutTimer_.tv_usec = (timeout - seconds).count();
|
||||
timeoutCallback_ = callback;
|
||||
ThreadWakeup();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DliWatcher::Start()
|
||||
{
|
||||
if (running_.exchange(true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
if (pipe(wakeupPipe_) != 0) {
|
||||
HDF_LOGE("DliWatcher create pipe failed.");
|
||||
running_.exchange(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
thread_ = std::thread(std::bind(&DliWatcher::WatcherThread, this));
|
||||
if (!thread_.joinable()) {
|
||||
HDF_LOGE("thread is not joinable.");
|
||||
running_.exchange(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
int policy = SLE_THREAD_POLICY;
|
||||
sched_param params = {.sched_priority = SLE_THREAD_PRIORITY};
|
||||
if (pthread_setschedparam(thread_.native_handle(), policy, ¶ms) != 0) {
|
||||
HDF_LOGW("pthread_setschedparam failed tid[%{public}lu] policy[%{public}d]", thread_.native_handle(), policy);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DliWatcher::Stop()
|
||||
{
|
||||
if (!running_.exchange(false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadWakeup();
|
||||
thread_.join();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
close(wakeupPipe_[0]);
|
||||
close(wakeupPipe_[1]);
|
||||
}
|
||||
HDF_LOGI("DliWatcher stop");
|
||||
return true;
|
||||
}
|
||||
|
||||
void DliWatcher::CheckFdReady(std::map<int, DliDataCallback>& fds, fd_set &readFds)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fdsMutex_);
|
||||
for (auto &&fd : fds_) {
|
||||
if (FD_ISSET(fd.first, &readFds)) {
|
||||
fd.second(fd.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DliWatcher::InitReadFds(fd_set &readFds, int &nfds)
|
||||
{
|
||||
FD_ZERO(&readFds);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
FD_SET(wakeupPipe_[0], &readFds);
|
||||
nfds = wakeupPipe_[0];
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fdsMutex_);
|
||||
for (auto &&fd : fds_) {
|
||||
FD_SET(fd.first, &readFds);
|
||||
nfds = std::max(fd.first, nfds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DliWatcher::HandleTimeout()
|
||||
{
|
||||
TimeoutCallback callback;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(timeoutMutex_);
|
||||
callback = timeoutCallback_;
|
||||
}
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
void DliWatcher::HandleSelectEvent(fd_set &readFds)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
if (FD_ISSET(wakeupPipe_[0], &readFds)) {
|
||||
uint8_t buff = 0;
|
||||
TEMP_FAILURE_RETRY(read(wakeupPipe_[0], &buff, sizeof(buff)));
|
||||
}
|
||||
}
|
||||
if (running_) {
|
||||
CheckFdReady(fds_, readFds);
|
||||
}
|
||||
}
|
||||
|
||||
void DliWatcher::WatcherThread()
|
||||
{
|
||||
fd_set readFds;
|
||||
int nfds;
|
||||
timeval *timeout = nullptr;
|
||||
|
||||
while (running_) {
|
||||
InitReadFds(readFds, nfds);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(timeoutMutex_);
|
||||
if (timeoutTimer_.tv_sec == 0 && timeoutTimer_.tv_usec == 0) {
|
||||
timeout = nullptr;
|
||||
} else {
|
||||
timeout = &timeoutTimer_;
|
||||
}
|
||||
}
|
||||
int ret = select(nfds + 1, &readFds, nullptr, nullptr, timeout);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
} else if (ret == 0) {
|
||||
HandleTimeout();
|
||||
} else {
|
||||
HandleSelectEvent(readFds);
|
||||
}
|
||||
}
|
||||
HDF_LOGI("DliWatcher thread is stop!");
|
||||
}
|
||||
|
||||
void DliWatcher::ThreadWakeup()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
uint8_t buff = 0;
|
||||
ssize_t ret = TEMP_FAILURE_RETRY(write(wakeupPipe_[1], &buff, sizeof(buff)));
|
||||
if (ret == -1) {
|
||||
HDF_LOGE("wake up failed err:%{public}s", strerror(errno));
|
||||
}
|
||||
}
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_DLI_WATCHER_H
|
||||
#define OHOS_HDI_NEARLINK_DLI_WATCHER_H
|
||||
|
||||
#include <atomic>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <sys/time.h>
|
||||
#include <thread>
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
class DliWatcher {
|
||||
public:
|
||||
using DliDataCallback = std::function<void(int fd)>;
|
||||
using TimeoutCallback = std::function<void()>;
|
||||
|
||||
DliWatcher();
|
||||
~DliWatcher();
|
||||
|
||||
bool AddFdToWatcher(int fd, DliDataCallback callback);
|
||||
bool RemoveFdToWatcher(int fd);
|
||||
bool SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback);
|
||||
bool Start();
|
||||
bool Stop();
|
||||
|
||||
private:
|
||||
void CheckFdReady(std::map<int, DliDataCallback>& fds, fd_set &readFds);
|
||||
void InitReadFds(fd_set &readFds, int &nfds);
|
||||
void HandleTimeout();
|
||||
void HandleSelectEvent(fd_set &readFds);
|
||||
void WatcherThread();
|
||||
void ThreadWakeup();
|
||||
|
||||
private:
|
||||
std::atomic_bool running_ = {false};
|
||||
std::map<int, DliDataCallback> fds_;
|
||||
std::mutex fdsMutex_;
|
||||
std::mutex wakeupPipeMutex_;
|
||||
int wakeupPipe_[2] = {0};
|
||||
timeval timeoutTimer_ = {};
|
||||
TimeoutCallback timeoutCallback_;
|
||||
std::mutex timeoutMutex_;
|
||||
std::thread thread_;
|
||||
};
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_NEARLINK_DLI_WATCHER_H */
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include "nearlink_hdf_log.h"
|
||||
#include "h4_protocol.h"
|
||||
#include <unistd.h>
|
||||
#include "sle_hal_constant.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
constexpr const char *SLE_MAC_LIB = "libnearlink_mac.z.so";
|
||||
constexpr const char *SET_VIP_PRIO = "SetVipPrio";
|
||||
constexpr int NEARLINK_HOST_PRIORITY = 10;
|
||||
|
||||
thread_local bool H4Protocol::isThreadPromoted = false;
|
||||
|
||||
H4Protocol::H4Protocol(
|
||||
int fd, DliDataCallback onAcbReceive, DliDataCallback onIcbReceive, DliDataCallback onEventReceive)
|
||||
: dliFd_(fd), onAcbReceive_(onAcbReceive), onIcbReceive_(onIcbReceive), onEventReceive_(onEventReceive)
|
||||
{}
|
||||
|
||||
ssize_t H4Protocol::SendPacket(const std::vector<uint8_t> &packetData)
|
||||
{
|
||||
SetRTSchedule();
|
||||
ssize_t writtenNumber = 0;
|
||||
ssize_t ret = 0;
|
||||
do {
|
||||
ret = Write(dliFd_, packetData.data() + writtenNumber, packetData.size() - writtenNumber);
|
||||
if (ret > 0) {
|
||||
writtenNumber += ret;
|
||||
} else if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
} while (static_cast<size_t>(writtenNumber) != packetData.size());
|
||||
return writtenNumber;
|
||||
}
|
||||
|
||||
static bool ReadLengthCheck(ssize_t readLen, char *buf, int fd)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
if (readLen < 0) {
|
||||
strerror_r(errno, buf, bufsize);
|
||||
HDF_LOGE("read fd[%{public}d] fail", fd);
|
||||
return false;
|
||||
} else if (readLen == 0) {
|
||||
HDF_LOGE("read fd[%{public}d] readLen = 0.", fd);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void H4Protocol::ReadData(int fd)
|
||||
{
|
||||
SetRTSchedule();
|
||||
const int bufsize = 256;
|
||||
char buf[bufsize] = {0};
|
||||
static uint8_t typeNo{0};
|
||||
ssize_t readLen = 0;
|
||||
if (dliPacket_.size() == 0) {
|
||||
readLen = Read(fd, &packetType_, sizeof(packetType_));
|
||||
NL_HDF_CHECK_RETURN(readLen > 0, "read fd[%{public}d], readLen[%{public}zd]", fd, readLen);
|
||||
typeNo = (packetType_) & 0x0F;
|
||||
if (packetType_ > DLI_PACKET_TYPE_UNKNOWN && packetType_ < DLI_PACKET_TYPE_MAX) {
|
||||
dliPacket_.resize(header_[typeNo].headerSize);
|
||||
}
|
||||
} else if (dliPacket_.size() == header_[typeNo].headerSize) {
|
||||
readLen = Read(fd, dliPacket_.data() + readLength_, dliPacket_.size() - readLength_);
|
||||
NL_HDF_CHECK_RETURN(ReadLengthCheck(readLen, buf, fd),
|
||||
"hciPacket size[%{public}zu], readLength[%{public}u]", dliPacket_.size(), readLength_);
|
||||
readLength_ += readLen;
|
||||
if (readLength_ == dliPacket_.size()) {
|
||||
size_t dataLen = 0;
|
||||
for (int ii = 0; ii < header_[typeNo].dataLengthSize; ii++) {
|
||||
dataLen += (dliPacket_[header_[typeNo].dataLengthOffset + ii] << (ii * 0x08));
|
||||
}
|
||||
if (dataLen == 0) {
|
||||
HDF_LOGE("dataLen == 0, proc data error.");
|
||||
dliPacket_.clear();
|
||||
readLength_ = 0;
|
||||
typeNo = 0;
|
||||
} else {
|
||||
dliPacket_.resize(dliPacket_.size() + dataLen);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
readLen = Read(fd, dliPacket_.data() + readLength_, dliPacket_.size() - readLength_);
|
||||
NL_HDF_CHECK_RETURN(ReadLengthCheck(readLen, buf, fd),
|
||||
"hciPacket size[%{public}zu], readLength[%{public}u]", dliPacket_.size(), readLength_);
|
||||
readLength_ += readLen;
|
||||
if (readLength_ == dliPacket_.size()) {
|
||||
PacketCallback();
|
||||
dliPacket_.clear();
|
||||
readLength_ = 0;
|
||||
typeNo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
H4Protocol::~H4Protocol() {}
|
||||
|
||||
void H4Protocol::PacketCallback()
|
||||
{
|
||||
switch (packetType_) {
|
||||
case DLI_PACKET_TYPE_SLE_ACB_DATA:
|
||||
if (onAcbReceive_) {
|
||||
onAcbReceive_(dliPacket_);
|
||||
}
|
||||
break;
|
||||
case DLI_PACKET_TYPE_SLE_ICB_DATA:
|
||||
if (onIcbReceive_) {
|
||||
onIcbReceive_(dliPacket_);
|
||||
}
|
||||
break;
|
||||
case DLI_PACKET_TYPE_SLE_EVENT:
|
||||
if (onEventReceive_) {
|
||||
onEventReceive_(dliPacket_);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
HDF_LOGE("PacketCallback type[%{public}d] error.", packetType_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetVipPrio(unsigned int vipPrio)
|
||||
{
|
||||
void *libMac = dlopen(SLE_MAC_LIB, RTLD_LAZY);
|
||||
if (libMac == nullptr) {
|
||||
HDF_LOGI("SetVipPrio no mac lib ready for dlopen");
|
||||
return false;
|
||||
}
|
||||
using GetMacFun = bool (*)(unsigned int);
|
||||
GetMacFun setVipPrio = reinterpret_cast<GetMacFun>(dlsym(libMac, SET_VIP_PRIO));
|
||||
if (setVipPrio == nullptr) {
|
||||
HDF_LOGE("SetVipPrio dlsym error");
|
||||
dlclose(libMac);
|
||||
return false;
|
||||
}
|
||||
bool result = false;
|
||||
result = setVipPrio(vipPrio);
|
||||
dlclose(libMac);
|
||||
return result;
|
||||
}
|
||||
|
||||
void H4Protocol::SetRTSchedule()
|
||||
{
|
||||
if (isThreadPromoted) {
|
||||
return;
|
||||
}
|
||||
SetVipPrio(NEARLINK_HOST_PRIORITY);
|
||||
pid_t tid = gettid();
|
||||
struct sched_param rtParams = {.sched_priority = SLE_THREAD_PRIORITY};
|
||||
int rc = sched_setscheduler(tid, SCHED_FIFO, &rtParams);
|
||||
isThreadPromoted = (rc != 0) ? false : true;
|
||||
}
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_DLI_H4_PROTOCOL_H
|
||||
#define OHOS_HDI_NEARLINK_DLI_H4_PROTOCOL_H
|
||||
|
||||
#include "dli_protocol.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
class H4Protocol : public DliProtocol {
|
||||
public:
|
||||
H4Protocol(int fd, DliDataCallback onAcbReceive, DliDataCallback onIcbReceive, DliDataCallback onEventReceive);
|
||||
|
||||
ssize_t SendPacket(const std::vector<uint8_t> &packetData) override;
|
||||
void ReadData(int fd);
|
||||
~H4Protocol() override;
|
||||
|
||||
private:
|
||||
void PacketCallback();
|
||||
void SetRTSchedule();
|
||||
|
||||
private:
|
||||
int dliFd_ = 0;
|
||||
DliDataCallback onAcbReceive_;
|
||||
DliDataCallback onIcbReceive_;
|
||||
DliDataCallback onEventReceive_;
|
||||
thread_local static bool isThreadPromoted;
|
||||
|
||||
uint8_t packetType_ = 0;
|
||||
|
||||
std::vector<uint8_t> dliPacket_;
|
||||
uint32_t readLength_ = 0;
|
||||
};
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
|
||||
#endif /* OHOS_HDI_NEARLINK_DLI_H4_PROTOCOL_H */
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NARLINK_HDF_LOG_H
|
||||
#define NARLINK_HDF_LOG_H
|
||||
|
||||
#include <hdf_log.h>
|
||||
|
||||
#ifdef LOG_DOMAIN
|
||||
#undef LOG_DOMAIN
|
||||
#endif
|
||||
#define LOG_DOMAIN 0xD000154
|
||||
|
||||
#ifndef HDF_LOG_TAG
|
||||
#define HDF_LOG_TAG nearlink_hdf
|
||||
#endif
|
||||
|
||||
#ifdef NL_HDF_CHECK_RETURN
|
||||
#undef NL_HDF_CHECK_RETURN
|
||||
#endif
|
||||
|
||||
#define NL_HDF_CHECK_RETURN(cond, fmt, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
HDF_LOGE(fmt, ##__VA_ARGS__); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // NARLINK_HDF_LOG_H
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SLE_VENDOR_LIB_H
|
||||
#define SLE_VENDOR_LIB_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Define DLI channel descriptors array used in SLE_OP_DLI_CHANNEL_OPEN operation.
|
||||
*/
|
||||
typedef enum {
|
||||
DLI_CMD, // DLI Command channel
|
||||
DLI_EVT, // DLI Event channel
|
||||
DLI_ACB_OUT, // DLI ACB downstream channel
|
||||
DLI_ACB_IN, // DLI ACB upstream channel
|
||||
DLI_MAX_CHANNEL // Total channels
|
||||
} DliChannelsT;
|
||||
|
||||
typedef enum {
|
||||
SLE_OP_RESULT_SUCCESS,
|
||||
SLE_OP_RESULT_FAIL,
|
||||
} SleOpResultT;
|
||||
|
||||
/**
|
||||
* SLE vendor lib cmd.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* Power on the SLE Controller.
|
||||
* @return 0 if success.
|
||||
*/
|
||||
SLE_OP_POWER_ON,
|
||||
|
||||
/**
|
||||
* Power off the SLE Controller.
|
||||
* @return 0 if success.
|
||||
*/
|
||||
SLE_OP_POWER_OFF,
|
||||
|
||||
/**
|
||||
* Establish dli channels. it will be called after SLE_OP_POWER_ON.
|
||||
* @param int (*)[DLI_MAX_CHANNEL].
|
||||
* @return fd count.
|
||||
*/
|
||||
SLE_OP_DLI_CHANNEL_OPEN,
|
||||
|
||||
/**
|
||||
* Close all the dli channels which is opened.
|
||||
*/
|
||||
SLE_OP_DLI_CHANNEL_CLOSE,
|
||||
|
||||
/**
|
||||
* initialization the SLE Controller. it will be called after SLE_OP_DLI_CHANNEL_OPEN.
|
||||
* Controller Must call initCb to notify the host once it has been done.
|
||||
*/
|
||||
SLE_OP_INIT,
|
||||
|
||||
/**
|
||||
* Get the LPM idle timeout in milliseconds.
|
||||
* @param (uint_32 *)milliseconds, slec will return the value of lpm timer.
|
||||
* @return 0 if success.
|
||||
*/
|
||||
SLE_OP_GET_LPM_TIMER,
|
||||
|
||||
/**
|
||||
* Enable LPM mode on SLE Controller.
|
||||
*/
|
||||
SLE_OP_LPM_ENABLE,
|
||||
|
||||
/**
|
||||
* Disable LPM mode on SLE Controller.
|
||||
*/
|
||||
SLE_OP_LPM_DISABLE,
|
||||
|
||||
/**
|
||||
* Wakeup lock the SLEC.
|
||||
*/
|
||||
SLE_OP_WAKEUP_LOCK,
|
||||
|
||||
/**
|
||||
* Wakeup unlock the SLEC.
|
||||
*/
|
||||
SLE_OP_WAKEUP_UNLOCK,
|
||||
|
||||
/**
|
||||
* transmit event response to vendor lib.
|
||||
* @param (void *)buf, struct of HC_SLE_HDR.
|
||||
*/
|
||||
SLE_OP_EVENT_CALLBACK
|
||||
} SleOpcodeT;
|
||||
|
||||
/**
|
||||
* initialization callback.
|
||||
*/
|
||||
typedef void (*InitCallback)(SleOpResultT result);
|
||||
|
||||
/**
|
||||
* Nearlink Host/Controller VENDOR Interface
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* Set to sizeof(sle_vndor_interface_t)
|
||||
*/
|
||||
size_t size;
|
||||
|
||||
/**
|
||||
* Caller will open the interface and pass in the callback routines
|
||||
* to the implementation of this interface.
|
||||
*/
|
||||
int (*init)(void);
|
||||
|
||||
/**
|
||||
* Vendor specific operations
|
||||
*/
|
||||
int (*op)(int opcode, void* param);
|
||||
|
||||
/**
|
||||
* Closes the interface
|
||||
*/
|
||||
void (*close)(void);
|
||||
} SleVendorInterfaceT;
|
||||
|
||||
typedef struct {
|
||||
uint16_t event;
|
||||
uint16_t len;
|
||||
uint16_t offset;
|
||||
uint16_t layerSpecific;
|
||||
uint8_t data[];
|
||||
} HC_SLE_HDR;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SLE_VENDOR_LIB_H */
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include "securec.h"
|
||||
#include "dli_internal.h"
|
||||
#include "nearlink_hdf_log.h"
|
||||
#include "sle_address.h"
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
namespace {
|
||||
constexpr int ADDRESS_STR_LEN = 17;
|
||||
constexpr int ADDRESS_SIZE = 6;
|
||||
constexpr const char *SLE_MAC_LIB = "libnearlink_mac.z.so";
|
||||
constexpr const char *GET_SLE_MAC_SYMBOL_NAME = "GetConstantMac";
|
||||
} // namespace
|
||||
|
||||
SleAddress::SleAddress()
|
||||
{
|
||||
address_.resize(ADDRESS_SIZE);
|
||||
}
|
||||
|
||||
constexpr int START_POS = 6;
|
||||
constexpr int END_POS = 13;
|
||||
constexpr int ADDR_BYTE = 18;
|
||||
std::string SleAddress::GetEncryptAddr(std::string addr)
|
||||
{
|
||||
if (addr.empty() || addr.length() != ADDRESS_STR_LEN) {
|
||||
HDF_LOGE("addr is invalid, length= %{public}zu", addr.length());
|
||||
return std::string("");
|
||||
}
|
||||
std::string tmp = "**:**:**:**:**:**";
|
||||
std::string out = addr;
|
||||
for (int i = START_POS; i <= END_POS; i++) {
|
||||
out[i] = tmp[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void SleAddress::ParseAddressToString(std::vector<uint8_t> &address, std::string &outString)
|
||||
{
|
||||
char temp[ADDR_BYTE] = {0};
|
||||
int ret = sprintf_s(temp, sizeof(temp), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
address[0], address[1], address[2], address[3], address[4], address[5]);
|
||||
if (ret == -1) {
|
||||
HDF_LOGE("ConvertAddr sprintf_s return error, ret -1");
|
||||
}
|
||||
outString = temp;
|
||||
}
|
||||
|
||||
int SleAddress::ParseAddressFromString(const std::string &string) const
|
||||
{
|
||||
size_t offset = 0;
|
||||
int bytesIndex = 0;
|
||||
int readCount = 0;
|
||||
for (bytesIndex = 0; bytesIndex < ADDRESS_SIZE && offset < string.size(); bytesIndex++) {
|
||||
readCount = 0;
|
||||
if (sscanf_s(&string[offset], "%02hhx:%n", &address_[bytesIndex], &readCount) > 0) {
|
||||
if (readCount == 0 && bytesIndex != ADDRESS_SIZE - 1) {
|
||||
return bytesIndex;
|
||||
}
|
||||
offset += static_cast<uint32_t>(readCount);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bytesIndex;
|
||||
}
|
||||
|
||||
bool SleAddress::GetConstantAddress(char *address, int len)
|
||||
{
|
||||
if (address == nullptr || len < ADDRESS_STR_LEN + 1) {
|
||||
HDF_LOGE("GetConstantAddress buf error");
|
||||
return false;
|
||||
}
|
||||
|
||||
void *libMac = dlopen(SLE_MAC_LIB, RTLD_LAZY);
|
||||
if (libMac == nullptr) {
|
||||
HDF_LOGI("GetConstantAddress no mac lib ready for dlopen");
|
||||
return false;
|
||||
}
|
||||
|
||||
using GetMacFun = int (*)(char*, int);
|
||||
GetMacFun getMac = reinterpret_cast<GetMacFun>(dlsym(libMac, GET_SLE_MAC_SYMBOL_NAME));
|
||||
if (getMac == nullptr) {
|
||||
HDF_LOGE("GetConstantAddress dlsym error");
|
||||
dlclose(libMac);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = getMac(address, len);
|
||||
HDF_LOGI("GetConstantAddress ret: %{public}d", ret);
|
||||
dlclose(libMac);
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
#ifdef RELOAD_ADDRESS
|
||||
// system boot less 2min, need ReadSleAddress from NV
|
||||
bool SleAddress::NeedReloadAddress()
|
||||
{
|
||||
const int64_t maxNeedReloadTime = 120000; // 120s
|
||||
constexpr int64_t msPerSecond = 1000;
|
||||
constexpr int64_t nsPerMs = 1000000;
|
||||
struct timespec times = {0};
|
||||
if (clock_gettime(CLOCK_MONOTONIC, ×) < 0) {
|
||||
HDF_LOGE("Failed clock_gettime:%{public}s, needReloadAddress:false", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
int64_t relativeTime = ((times.tv_sec * msPerSecond) + (times.tv_nsec / nsPerMs));
|
||||
HDF_LOGI("relativeTime:%{public}lu", relativeTime);
|
||||
return relativeTime < maxNeedReloadTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::shared_ptr<SleAddress> SleAddress::UpdateAddressFromNV(const std::string &path)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
char buf[bufsize] = {0};
|
||||
int newFd = open(path.c_str(), O_RDWR | O_CREAT, 00644);
|
||||
HDF_LOGI("GetDeviceAddress open newFd %{public}d.", newFd);
|
||||
char addressStr[ADDRESS_STR_LEN + 1] = {"00:11:22:33:44:55"};
|
||||
bool readNVSucc = GetConstantAddress(addressStr, ADDRESS_STR_LEN + 1);
|
||||
bool needUpdateTxt = true;
|
||||
if (newFd < 0) {
|
||||
auto ptr = std::make_shared<SleAddress>();
|
||||
int ret = ptr->ParseAddressFromString(addressStr);
|
||||
if (ret != ADDRESS_SIZE) {
|
||||
HDF_LOGE("UpdateAddressFromNV ParseAddressFromString failed, ret:%{public}d.", ret);
|
||||
return nullptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
if (!readNVSucc) {
|
||||
// read NV fail ,if slemac.txt exsit mac, not update, needUpdateTxt = false
|
||||
if (read(newFd, addressStr, ADDRESS_STR_LEN) != ADDRESS_STR_LEN) {
|
||||
auto tmpPtr = GenerateDeviceAddress();
|
||||
std::string strAddress;
|
||||
ParseAddressToString(tmpPtr->address_, strAddress);
|
||||
HDF_LOGI("device mac addr: %{public}s", GetEncryptAddr(strAddress).c_str());
|
||||
int ret = strcpy_s(addressStr, ADDRESS_STR_LEN + 1, strAddress.c_str());
|
||||
if (ret != 0) {
|
||||
HDF_LOGE("ParseAddressToString strcpy_s err!");
|
||||
}
|
||||
} else {
|
||||
HDF_LOGI("newFd %{public}d not update", newFd);
|
||||
needUpdateTxt = false;
|
||||
}
|
||||
}
|
||||
if (needUpdateTxt) {
|
||||
int fdRet = write(newFd, addressStr, ADDRESS_STR_LEN);
|
||||
if (fdRet < 0) {
|
||||
strerror_r(errno, buf, sizeof(buf));
|
||||
HDF_LOGE("GetDeviceAddress addr write failed, err:%{public}s.", buf);
|
||||
}
|
||||
}
|
||||
close(newFd);
|
||||
auto ptr = std::make_shared<SleAddress>();
|
||||
int result = ptr->ParseAddressFromString(addressStr);
|
||||
if (result != ADDRESS_SIZE) {
|
||||
HDF_LOGE("UpdateAddressFromNV ParseAddressFromString failed, result:%{public}d.", result);
|
||||
return nullptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SleAddress> SleAddress::GetDeviceAddress(const std::string &path)
|
||||
{
|
||||
#ifdef RELOAD_ADDRESS
|
||||
if (NeedReloadAddress()) {
|
||||
return UpdateAddressFromNV(path);
|
||||
}
|
||||
#endif
|
||||
int addrFd = open(path.c_str(), O_RDONLY);
|
||||
if (addrFd < 0) {
|
||||
return UpdateAddressFromNV(path);
|
||||
}
|
||||
char addressStr[ADDRESS_STR_LEN + 1] = {0};
|
||||
if (read(addrFd, addressStr, ADDRESS_STR_LEN) != ADDRESS_STR_LEN) {
|
||||
HDF_LOGE("read %{public}s failed.", path.c_str());
|
||||
close(addrFd);
|
||||
return UpdateAddressFromNV(path);
|
||||
}
|
||||
close(addrFd);
|
||||
auto ptr = std::make_shared<SleAddress>();
|
||||
int result = ptr->ParseAddressFromString(addressStr);
|
||||
if (result != ADDRESS_SIZE) {
|
||||
HDF_LOGE("GetDeviceAddress ParseAddressFromString failed, result:%{public}d.", result);
|
||||
return UpdateAddressFromNV(path);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SleAddress> SleAddress::GenerateDeviceAddress(const std::string &prefix)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
char buf[bufsize] = {0};
|
||||
auto ptr = std::make_shared<SleAddress>();
|
||||
char addressStr[ADDRESS_STR_LEN + 1] = {"00:11:22:33:44:55"};
|
||||
ptr->ParseAddressFromString(addressStr);
|
||||
int prefixCount = ptr->ParseAddressFromString(prefix);
|
||||
if (prefixCount < ADDRESS_SIZE) {
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
strerror_r(errno, buf, sizeof(buf));
|
||||
HDF_LOGE("open /dev/urandom failed err:%{public}s.", buf);
|
||||
return ptr;
|
||||
}
|
||||
if (read(fd, &ptr->address_[prefixCount], ADDRESS_SIZE - prefixCount) != ADDRESS_SIZE - prefixCount) {
|
||||
strerror_r(errno, buf, sizeof(buf));
|
||||
HDF_LOGE("read /dev/urandom failed err:%{public}s.", buf);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void SleAddress::ReadAddress(std::vector<uint8_t> &address) const
|
||||
{
|
||||
address = address_;
|
||||
}
|
||||
|
||||
void SleAddress::ReadAddress(std::string &address) const
|
||||
{
|
||||
address.resize(ADDRESS_STR_LEN + 1);
|
||||
|
||||
int offset = 0;
|
||||
for (int ii = 0; ii < ADDRESS_SIZE; ii++) {
|
||||
int ret = snprintf_s(
|
||||
&address[offset], (ADDRESS_STR_LEN + 1) - offset, ADDRESS_STR_LEN - offset, "%02x:", address_[ii]);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
offset += ret;
|
||||
}
|
||||
}
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_HCI_NEARLINK_ADDRESS_H
|
||||
#define OHOS_HDI_NEARLINK_HCI_NEARLINK_ADDRESS_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "sle_hal_constant.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
class SleAddress {
|
||||
public:
|
||||
SleAddress();
|
||||
~SleAddress() = default;
|
||||
static std::shared_ptr<SleAddress> GetDeviceAddress(const std::string &path = SLE_DEVICE_ADDRESS_PATH);
|
||||
static std::shared_ptr<SleAddress> GenerateDeviceAddress(const std::string &prefix = "");
|
||||
static void ParseAddressToString(std::vector<uint8_t> &address, std::string &outString);
|
||||
static std::string GetEncryptAddr(std::string addr);
|
||||
void ReadAddress(std::vector<uint8_t> &address) const;
|
||||
void ReadAddress(std::string &address) const;
|
||||
|
||||
private:
|
||||
int ParseAddressFromString(const std::string &string) const;
|
||||
static bool GetConstantAddress(char *address, int len);
|
||||
#ifdef RELOAD_ADDRESS
|
||||
static bool NeedReloadAddress();
|
||||
#endif
|
||||
static std::shared_ptr<SleAddress> UpdateAddressFromNV(const std::string &path);
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> address_;
|
||||
};
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_NEARLINK_HCI_NEARLINK_ADDRESS_H */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_HCI_CONSTANT_H
|
||||
#define OHOS_HDI_NEARLINK_HCI_CONSTANT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
constexpr const char *SLE_VENDOR_NAME = "libnearlink_sle_vendor";
|
||||
constexpr const char *SLE_CHIP_TYPE = "const.nearlink.slechiptype";
|
||||
constexpr const char *SLE_VENDOR_INTERFACE_SYMBOL_NAME = "NEARLINK_VENDOR_LIB_INTERFACE";
|
||||
constexpr const char *SLE_DEVICE_ADDRESS_PATH = "/data/vendor/nearlink/slemac.txt";
|
||||
constexpr int SLE_THREAD_POLICY = SCHED_RR;
|
||||
constexpr int SLE_THREAD_PRIORITY = 1;
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
|
||||
#endif /* OHOS_HDI_NEARLINK_HCI_CONSTANT_H */
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "thread_util.h"
|
||||
#include <mutex>
|
||||
#include "ffrt_inner.h"
|
||||
#include <hdf_log.h>
|
||||
#include "nearlink_hdf_log.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
|
||||
void DoInDliThread(const ThreadUtilFunc &func)
|
||||
{
|
||||
ThreadUtil::GetInstance().PostTask(func);
|
||||
}
|
||||
|
||||
struct ThreadUtil::impl {
|
||||
class TaskQueue {
|
||||
public:
|
||||
explicit TaskQueue(const char *name) : queue_(name, ffrt::queue_attr().qos(ffrt::qos_user_interactive)) {}
|
||||
~TaskQueue() = default;
|
||||
|
||||
void PostTask(const ThreadUtilFunc &func);
|
||||
int GetQueueId(void);
|
||||
|
||||
private:
|
||||
ffrt::queue queue_;
|
||||
};
|
||||
|
||||
impl();
|
||||
~impl() = default;
|
||||
std::shared_ptr<TaskQueue> CreateTaskQueue();
|
||||
|
||||
std::shared_ptr<TaskQueue> taskQueue;
|
||||
};
|
||||
|
||||
ThreadUtil::impl::impl()
|
||||
{}
|
||||
|
||||
ThreadUtil::ThreadUtil() : pimpl(std::make_unique<impl>())
|
||||
{}
|
||||
|
||||
ThreadUtil::~ThreadUtil()
|
||||
{}
|
||||
|
||||
void ThreadUtil::impl::TaskQueue::PostTask(const ThreadUtilFunc &func)
|
||||
{
|
||||
queue_.submit(func);
|
||||
}
|
||||
|
||||
int ThreadUtil::impl::TaskQueue::GetQueueId(void)
|
||||
{
|
||||
int id = -1;
|
||||
auto handle = queue_.submit_h([&id]() {
|
||||
id = ffrt::get_queue_id();
|
||||
});
|
||||
queue_.wait(handle);
|
||||
return id;
|
||||
}
|
||||
|
||||
void ThreadUtil::PostTask(const ThreadUtilFunc &func)
|
||||
{
|
||||
std::shared_ptr<impl::TaskQueue> taskQueue = pimpl->taskQueue;
|
||||
if (taskQueue != nullptr) {
|
||||
taskQueue->PostTask(func);
|
||||
return;
|
||||
}
|
||||
// If the thread not found, create it.
|
||||
taskQueue = pimpl->CreateTaskQueue();
|
||||
// Execute the first task.
|
||||
if (taskQueue) {
|
||||
taskQueue->PostTask(func);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ThreadUtil::impl::TaskQueue> ThreadUtil::impl::CreateTaskQueue()
|
||||
{
|
||||
std::string threadName = "sle_hci";
|
||||
auto taskQueue_ = std::make_shared<TaskQueue>(threadName.c_str());
|
||||
|
||||
int queueId = taskQueue_->GetQueueId();
|
||||
HDF_LOGI("sle_ffrt_queue: queueId(%{public}d), name(%{public}s)", queueId, threadName.c_str());
|
||||
|
||||
taskQueue = taskQueue_;
|
||||
return taskQueue_;
|
||||
}
|
||||
|
||||
ThreadUtil &ThreadUtil::GetInstance()
|
||||
{
|
||||
static ThreadUtil instance;
|
||||
return instance;
|
||||
}
|
||||
} // namespace Nearlink
|
||||
} // namepsace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SLE_THREAD_UTIL_H
|
||||
#define SLE_THREAD_UTIL_H
|
||||
|
||||
#include <functional>
|
||||
#ifdef RESOURCESCHEDULE_FFRT_ENABLE
|
||||
#include "ffrt_inner.h"
|
||||
#include <hdf_log.h>
|
||||
#include "nearlink_hdf_log.h"
|
||||
#else
|
||||
#include <mutex>
|
||||
#endif // RESOURCESCHEDULE_FFRT_ENABLE
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
|
||||
using ThreadUtilFunc = std::function<void(void)>;
|
||||
|
||||
/**
|
||||
* @brief Post the task to the dli thread.
|
||||
* @param func The task to be executed.
|
||||
*/
|
||||
void DoInDliThread(const ThreadUtilFunc &func);
|
||||
|
||||
class ThreadUtil {
|
||||
public:
|
||||
void PostTask(const ThreadUtilFunc &func);
|
||||
static ThreadUtil &GetInstance();
|
||||
private:
|
||||
ThreadUtil();
|
||||
~ThreadUtil();
|
||||
|
||||
struct impl;
|
||||
std::unique_ptr<impl> pimpl;
|
||||
};
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
|
||||
#endif // SLE_THREAD_UTIL_H
|
||||
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <thread>
|
||||
#include <dlfcn.h>
|
||||
#include <future>
|
||||
#include <securec.h>
|
||||
#include "common_timer_errors.h"
|
||||
#include "nearlink_hdf_log.h"
|
||||
#include "sle_address.h"
|
||||
#include "sle_hal_constant.h"
|
||||
#include "timer.h"
|
||||
#include "h4_protocol.h"
|
||||
#include "vendor_interface.h"
|
||||
#include "parameters.h"
|
||||
#include "thread_util.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
namespace V1_1 {
|
||||
|
||||
constexpr size_t DLI_PACKET_TYPE_SIZE = 1;
|
||||
constexpr uint16_t DLI_SET_SLE_ADDR = 0x0405;
|
||||
/* Define the preamble length for all DLI Commands. This is 2-bytes for opcode and 2 byte for length */
|
||||
constexpr size_t DLIC_PREAMBLE_SIZE = 4;
|
||||
/* Device address length */
|
||||
constexpr int BD_ADDR_LEN = 6;
|
||||
constexpr int OFFSET_EIGHT_BITS = 8;
|
||||
constexpr int OFFSET_STATUS = 3;
|
||||
constexpr size_t SLE_VENDOR_INVALID_DATA_LEN = 0;
|
||||
constexpr int DLI_INTERFACE_CLOSED = 0;
|
||||
constexpr int DLI_INTERFACE_OPENING = 1;
|
||||
constexpr int DLI_INTERFACE_OPENED = 2;
|
||||
constexpr int SET_ADDR_TIME_OUT_MS = 200;
|
||||
|
||||
struct InternalCommand {
|
||||
uint16_t cb;
|
||||
uint16_t opcode;
|
||||
};
|
||||
|
||||
struct TaskConfig {
|
||||
pid_t pid;
|
||||
unsigned int value;
|
||||
};
|
||||
|
||||
#define SET_VIP_PRIO 25
|
||||
#define PERF_CTRL_MAGIC 'x'
|
||||
#define PERF_CTRL_SET_VIP_PRIO \
|
||||
_IOW(PERF_CTRL_MAGIC, SET_VIP_PRIO, struct TaskConfig)
|
||||
|
||||
class VendorInterface::Impl {
|
||||
public:
|
||||
bool Initialize(VendorInterface::InitializeCompleteCallback initializeCompleteCallback,
|
||||
const VendorInterface::ReceiveCallback &receiveCallback);
|
||||
void CleanUp();
|
||||
size_t SendPacket(const std::vector<uint8_t> &packet);
|
||||
void SetSleAddress(uint8_t *localSleAddr);
|
||||
uint8_t *TransformAddress(uint8_t *addr);
|
||||
void OnEventReceived(const std::vector<uint8_t> &data);
|
||||
void OnAcbReceived(const std::vector<uint8_t> &data);
|
||||
void OnIcbReceived(const std::vector<uint8_t> &data);
|
||||
void SetSleAddressTimeOut();
|
||||
|
||||
public:
|
||||
std::mutex setAddrFinishedMutex_ {};
|
||||
bool isSetAddrFinished_ = false; // guarded by setAddrFinishedMutex_
|
||||
std::condition_variable setAddrConditionVariable_ {};
|
||||
std::shared_ptr<Dli::DliProtocol> dli_ = nullptr;
|
||||
|
||||
private:
|
||||
void OnInitCallback(SleOpResultT result);
|
||||
bool WatchDliChannel(const VendorInterface::ReceiveCallback &receiveCallback);
|
||||
void WatcherTimeout();
|
||||
void GetFullVendorName(std::string &name);
|
||||
|
||||
private:
|
||||
VendorInterface::InitializeCompleteCallback initializeCompleteCallback_;
|
||||
ReceiveDataCallback eventDataCallback_ = nullptr;
|
||||
ReceiveDataCallback acbDataCallback_ = nullptr;
|
||||
ReceiveDataCallback icbDataCallback_ = nullptr;
|
||||
void* vendorHandle_ = nullptr;
|
||||
SleVendorInterfaceT *vendorInterface_ = nullptr;
|
||||
DliWatcher watcher_;
|
||||
uint32_t lpmTimer_ = 0;
|
||||
InternalCommand internalCommand_ = {0, 0};
|
||||
std::shared_ptr<SleAddress> sleAddress_ = nullptr;
|
||||
int dliInterfaceState_ = DLI_INTERFACE_CLOSED;
|
||||
};
|
||||
|
||||
VendorInterface::VendorInterface() : impl_(std::make_unique<Impl>())
|
||||
{
|
||||
HDF_LOGI("VendorInterface Constructor.");
|
||||
}
|
||||
|
||||
VendorInterface::~VendorInterface()
|
||||
{
|
||||
HDF_LOGW("VendorInterface destructor.");
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
bool VendorInterface::Initialize(InitializeCompleteCallback initializeCompleteCallback,
|
||||
const ReceiveCallback &receiveCallback)
|
||||
{
|
||||
std::promise<bool> promise;
|
||||
vendorInterfaceWeak_ = shared_from_this();
|
||||
Nearlink::DoInDliThread([this, &initializeCompleteCallback, cb = receiveCallback, &promise]() {
|
||||
const ReceiveCallback &safeReceiveCallback = cb;
|
||||
bool result = impl_->Initialize(initializeCompleteCallback, safeReceiveCallback);
|
||||
promise.set_value(result);
|
||||
});
|
||||
return promise.get_future().get();
|
||||
}
|
||||
|
||||
void VendorInterface::CleanUp()
|
||||
{
|
||||
std::promise<void> promise;
|
||||
Nearlink::DoInDliThread([this, &promise]() {
|
||||
this->impl_->CleanUp();
|
||||
promise.set_value();
|
||||
});
|
||||
promise.get_future().get();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t VendorInterface::SendPacket(const std::vector<uint8_t> &packet)
|
||||
{
|
||||
std::promise<size_t> promise;
|
||||
Nearlink::DoInDliThread([this, packet_ = packet, &promise]() {
|
||||
const std::vector<uint8_t> &safePacket = packet_;
|
||||
size_t result = this->impl_->SendPacket(safePacket);
|
||||
promise.set_value(result);
|
||||
});
|
||||
return promise.get_future().get();
|
||||
}
|
||||
|
||||
void VendorInterface::OnEventReceived(const std::vector<uint8_t> &data)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl_->setAddrFinishedMutex_);
|
||||
if (impl_->isSetAddrFinished_ == false && impl_->dli_ != nullptr) {
|
||||
size_t opcodeOffset = impl_->dli_->GetPacketHeaderInfo(DLI_PACKET_TYPE_SLE_EVENT).headerSize;
|
||||
uint16_t opcode = data[opcodeOffset] | (data[opcodeOffset + 1] << OFFSET_EIGHT_BITS);
|
||||
if (opcode == DLI_SET_SLE_ADDR) {
|
||||
HDF_LOGI("SetSleAddress received the response");
|
||||
impl_->isSetAddrFinished_ = true;
|
||||
impl_->setAddrConditionVariable_.notify_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Nearlink::DoInDliThread([weakPtr = vendorInterfaceWeak_, data_ = data]() {
|
||||
auto vendorInterface = weakPtr.lock();
|
||||
if (vendorInterface == nullptr) {
|
||||
HDF_LOGE("VendorInterface::OnEventReceived: vendorInterface is nullptr");
|
||||
return;
|
||||
}
|
||||
vendorInterface->impl_->OnEventReceived(data_);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
void VendorInterface::OnAcbReceived(const std::vector<uint8_t> &data)
|
||||
{
|
||||
if (!impl_) {
|
||||
return;
|
||||
}
|
||||
impl_->OnAcbReceived(data);
|
||||
}
|
||||
|
||||
void VendorInterface::OnIcbReceived(const std::vector<uint8_t> &data)
|
||||
{
|
||||
Nearlink::DoInDliThread([weakPtr = vendorInterfaceWeak_, icbData = data]() {
|
||||
auto vendorInterface = weakPtr.lock();
|
||||
if (vendorInterface == nullptr) {
|
||||
HDF_LOGE("VendorInterface::OnIcbReceived: vendorInterface is nullptr");
|
||||
return;
|
||||
}
|
||||
vendorInterface->impl_->OnIcbReceived(icbData);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
bool VendorInterface::Impl::WatchDliChannel(const VendorInterface::ReceiveCallback &receiveCallback)
|
||||
{
|
||||
HDF_LOGI("VendorInterface %{public}s", __func__);
|
||||
int channel[DLI_MAX_CHANNEL] = {0};
|
||||
int channelCount = vendorInterface_->op(SleOpcodeT::SLE_OP_DLI_CHANNEL_OPEN, static_cast<void *>(channel));
|
||||
if (channelCount < 1 || channelCount > DLI_MAX_CHANNEL) {
|
||||
HDF_LOGE("VendorInterface vendorInterface_->op SLE_OP_DLI_CHANNEL_OPEN failed ret:%{public}d.", channelCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (channelCount == 1) {
|
||||
auto h4 = std::make_shared<Dli::H4Protocol>(channel[0],
|
||||
std::bind(&VendorInterface::OnAcbReceived, VendorInterface::GetInstance(),
|
||||
std::placeholders::_1),
|
||||
std::bind(&VendorInterface::OnIcbReceived, VendorInterface::GetInstance(),
|
||||
std::placeholders::_1),
|
||||
std::bind(&VendorInterface::OnEventReceived, VendorInterface::GetInstance(),
|
||||
std::placeholders::_1));
|
||||
watcher_.AddFdToWatcher(channel[0], std::bind(&Dli::H4Protocol::ReadData, h4, std::placeholders::_1));
|
||||
dli_ = h4;
|
||||
} else {
|
||||
HDF_LOGE("VendorInterface invalid channel count:%{public}d.", channelCount);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *VendorInterface::Impl::TransformAddress(uint8_t *addr)
|
||||
{
|
||||
HDF_LOGI("VendorInterface %{public}s", __func__);
|
||||
uint8_t* data = new (std::nothrow) uint8_t[DLI_PACKET_TYPE_SIZE + DLIC_PREAMBLE_SIZE + BD_ADDR_LEN];
|
||||
if (data == nullptr) {
|
||||
HDF_LOGE("failed to create data");
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t* p = data;
|
||||
*(p)++ = static_cast<uint8_t>(DLI_PACKET_TYPE_SLE_CMD);
|
||||
*(p)++ = static_cast<uint8_t>(DLI_SET_SLE_ADDR);
|
||||
*(p)++ = static_cast<uint8_t>(DLI_SET_SLE_ADDR >> OFFSET_EIGHT_BITS);
|
||||
*(p)++ = static_cast<uint8_t>(BD_ADDR_LEN);
|
||||
*(p)++ = static_cast<uint8_t>(0x00); // length domain is 2 bytes
|
||||
for (int i = 0; i < BD_ADDR_LEN; i++) {
|
||||
*(p)++ = static_cast<uint8_t>(addr[BD_ADDR_LEN - 1 - i]);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void VendorInterface::Impl::SetSleAddress(uint8_t *localSleAddr)
|
||||
{
|
||||
HDF_LOGI("VendorInterface %{public}s", __func__);
|
||||
if (dli_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface SetSleAddress dli_ is nullptr");
|
||||
return;
|
||||
}
|
||||
uint8_t *hciAddrPacket = TransformAddress(localSleAddr);
|
||||
if (hciAddrPacket == nullptr) {
|
||||
HDF_LOGE("VendorInterface SetSleAddress hciAddrPacket is nullptr");
|
||||
return;
|
||||
}
|
||||
std::vector<uint8_t> hciData(&hciAddrPacket[0],
|
||||
&hciAddrPacket[DLI_PACKET_TYPE_SIZE + DLIC_PREAMBLE_SIZE + BD_ADDR_LEN]);
|
||||
internalCommand_.cb = 1;
|
||||
internalCommand_.opcode = DLI_SET_SLE_ADDR;
|
||||
dli_->SendPacket(hciData);
|
||||
delete[] reinterpret_cast<uint8_t*>(hciAddrPacket);
|
||||
HDF_LOGI("VendorInterface send mac address complete. opcode: 0x%{public}04X, cb: %{public}hu",
|
||||
internalCommand_.opcode, internalCommand_.cb);
|
||||
}
|
||||
|
||||
void VendorInterface::Impl::GetFullVendorName(std::string &name)
|
||||
{
|
||||
std::string sleChipType = OHOS::system::GetParameter(SLE_CHIP_TYPE, "");
|
||||
HDF_LOGI("slechiptype is %{public}s", sleChipType.c_str());
|
||||
if (!sleChipType.empty()) {
|
||||
name.append("_");
|
||||
name.append(sleChipType.c_str());
|
||||
}
|
||||
name.append(".z.so");
|
||||
HDF_LOGI("sle vendor library name is %{public}s", name.c_str());
|
||||
}
|
||||
|
||||
bool VendorInterface::Impl::Initialize(VendorInterface::InitializeCompleteCallback initializeCompleteCallback,
|
||||
const VendorInterface::ReceiveCallback &receiveCallback)
|
||||
{
|
||||
HDF_LOGI("VendorInterface %{public}s", __func__);
|
||||
dliInterfaceState_ = DLI_INTERFACE_OPENING;
|
||||
initializeCompleteCallback_ = initializeCompleteCallback;
|
||||
eventDataCallback_ = receiveCallback.onEventReceive;
|
||||
acbDataCallback_ = receiveCallback.onAcbReceive;
|
||||
icbDataCallback_ = receiveCallback.onIcbReceive;
|
||||
std::string sleVendorFullName = SLE_VENDOR_NAME;
|
||||
GetFullVendorName(sleVendorFullName);
|
||||
vendorHandle_ = dlopen(sleVendorFullName.c_str(), RTLD_NOW);
|
||||
if (vendorHandle_ == nullptr) {
|
||||
HDF_LOGE("Vendor dlopen %{public}s failed, error code: %{public}s", sleVendorFullName.c_str(), dlerror());
|
||||
return false;
|
||||
}
|
||||
vendorInterface_ = reinterpret_cast<SleVendorInterfaceT *>(dlsym(vendorHandle_, SLE_VENDOR_INTERFACE_SYMBOL_NAME));
|
||||
if (vendorInterface_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface dlsym %{public}s failed.", SLE_VENDOR_INTERFACE_SYMBOL_NAME);
|
||||
return false;
|
||||
}
|
||||
sleAddress_ = SleAddress::GetDeviceAddress();
|
||||
std::vector<uint8_t> address = { 0, 0, 0, 0, 0, 0 };
|
||||
if (sleAddress_ != nullptr) {
|
||||
sleAddress_->ReadAddress(address);
|
||||
}
|
||||
vendorInterface_->init();
|
||||
if (!WatchDliChannel(receiveCallback)) {
|
||||
HDF_LOGE("VendorInterface WatchDliChannel failed.");
|
||||
return false;
|
||||
}
|
||||
if (!watcher_.Start()) {
|
||||
HDF_LOGE("VendorInterface watcher start failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sleAddress_ != nullptr) {
|
||||
std::string strAddress;
|
||||
sleAddress_->ParseAddressToString(address, strAddress);
|
||||
HDF_LOGI("VendorInterface local addr: %{public}s", sleAddress_->GetEncryptAddr(strAddress).c_str());
|
||||
}
|
||||
SetSleAddress(address.data());
|
||||
std::unique_lock<std::mutex> lock(setAddrFinishedMutex_);
|
||||
if (!setAddrConditionVariable_.wait_for(lock, std::chrono::milliseconds(SET_ADDR_TIME_OUT_MS),
|
||||
[this]() -> bool { return isSetAddrFinished_; })) {
|
||||
Nearlink::DoInDliThread([this]() -> void {
|
||||
SetSleAddressTimeOut();
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VendorInterface::Impl::CleanUp()
|
||||
{
|
||||
HDF_LOGI("VendorInterface %{public}s", __func__);
|
||||
if (vendorInterface_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface::CleanUp, vendorInterface_ is nullptr.");
|
||||
return;
|
||||
}
|
||||
watcher_.Stop();
|
||||
vendorInterface_->op(SleOpcodeT::SLE_OP_DLI_CHANNEL_CLOSE, nullptr);
|
||||
vendorInterface_->close();
|
||||
dli_ = nullptr;
|
||||
vendorInterface_ = nullptr;
|
||||
initializeCompleteCallback_ = nullptr;
|
||||
eventDataCallback_ = nullptr;
|
||||
acbDataCallback_ = nullptr;
|
||||
icbDataCallback_ = nullptr;
|
||||
if ((vendorHandle_ == nullptr) || dlclose(vendorHandle_)) {
|
||||
HDF_LOGE("VendorInterface vendorHandle_ is wrong.");
|
||||
}
|
||||
vendorHandle_ = nullptr;
|
||||
dliInterfaceState_ = DLI_INTERFACE_CLOSED;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(setAddrFinishedMutex_);
|
||||
isSetAddrFinished_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t VendorInterface::Impl::SendPacket(const std::vector<uint8_t> &packet)
|
||||
{
|
||||
HDF_LOGI("VendorInterface %{public}s", __func__);
|
||||
if (vendorInterface_ == nullptr || dli_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface::SendPacket, vendorInterface_ is nullptr.");
|
||||
return SLE_VENDOR_INVALID_DATA_LEN;
|
||||
}
|
||||
|
||||
watcher_.SetTimeout(std::chrono::milliseconds(lpmTimer_), std::bind(&Impl::WatcherTimeout, this));
|
||||
|
||||
return dli_->SendPacket(packet);
|
||||
}
|
||||
|
||||
// No lock is required through OnEventReceived invoking.
|
||||
void VendorInterface::Impl::OnInitCallback(SleOpResultT result)
|
||||
{
|
||||
HDF_LOGI("VendorInterface %{public}s, ", __func__);
|
||||
if (initializeCompleteCallback_) {
|
||||
initializeCompleteCallback_(result == SLE_OP_RESULT_SUCCESS);
|
||||
initializeCompleteCallback_ = nullptr;
|
||||
}
|
||||
|
||||
uint32_t lpmTimer = 0;
|
||||
lpmTimer_ = lpmTimer;
|
||||
watcher_.SetTimeout(std::chrono::milliseconds(lpmTimer), std::bind(&Impl::WatcherTimeout, this));
|
||||
}
|
||||
|
||||
void VendorInterface::Impl::OnEventReceived(const std::vector<uint8_t> &data)
|
||||
{
|
||||
HDF_LOGI("VendorInterface %{public}s", __func__);
|
||||
if (dliInterfaceState_ == DLI_INTERFACE_OPENED) {
|
||||
eventDataCallback_(data);
|
||||
return;
|
||||
}
|
||||
if (dli_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface OnEventReceived dli_ is nullptr");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t opcodeOffset = dli_->GetPacketHeaderInfo(DLI_PACKET_TYPE_SLE_EVENT).headerSize;
|
||||
if (data.size() <= opcodeOffset + OFFSET_STATUS) {
|
||||
HDF_LOGE("Invalid data length: %{public}zu", data.size());
|
||||
return;
|
||||
}
|
||||
uint16_t eventOpcode = data[0] | (data[1] << OFFSET_EIGHT_BITS);
|
||||
uint16_t opcode = data[opcodeOffset] | (data[opcodeOffset + 1] << OFFSET_EIGHT_BITS);
|
||||
if (internalCommand_.cb != 0 && (internalCommand_.opcode == opcode)) {
|
||||
internalCommand_.cb = 0;
|
||||
if (data[opcodeOffset + OFFSET_STATUS] == 0) {
|
||||
dliInterfaceState_ = DLI_INTERFACE_OPENED;
|
||||
OnInitCallback(SLE_OP_RESULT_SUCCESS);
|
||||
} else {
|
||||
HDF_LOGE("VendorInterface Invalid status: %{public}d", data[opcodeOffset + OFFSET_STATUS]);
|
||||
OnInitCallback(SLE_OP_RESULT_FAIL);
|
||||
CleanUp();
|
||||
}
|
||||
} else {
|
||||
HDF_LOGI("recv unexpected eventOpcode:0x%{public}x opcode:0x%{public}x", eventOpcode, opcode);
|
||||
}
|
||||
}
|
||||
|
||||
void VendorInterface::Impl::OnAcbReceived(const std::vector<uint8_t> &data)
|
||||
{
|
||||
if (acbDataCallback_ == nullptr) {
|
||||
HDF_LOGE("acbDataCallback_ is nullptr");
|
||||
return;
|
||||
}
|
||||
HDF_LOGD("VendorInterface %{public}s", __func__);
|
||||
acbDataCallback_(data);
|
||||
}
|
||||
|
||||
void VendorInterface::Impl::OnIcbReceived(const std::vector<uint8_t> &data)
|
||||
{
|
||||
if (icbDataCallback_ == nullptr) {
|
||||
HDF_LOGE("icbDataCallback_ is nullptr");
|
||||
return;
|
||||
}
|
||||
HDF_LOGD("VendorInterface %{public}s", __func__);
|
||||
icbDataCallback_(data);
|
||||
}
|
||||
|
||||
void VendorInterface::Impl::WatcherTimeout()
|
||||
{
|
||||
HDF_LOGI("fd wait out of time, no data ready");
|
||||
}
|
||||
|
||||
void VendorInterface::Impl::SetSleAddressTimeOut()
|
||||
{
|
||||
HDF_LOGI("SetSleAddressTimeOut, retry SetSleAddress");
|
||||
std::vector<uint8_t> address = { 0, 0, 0, 0, 0, 0 };
|
||||
if (sleAddress_ != nullptr) {
|
||||
sleAddress_->ReadAddress(address);
|
||||
}
|
||||
SetSleAddress(address.data());
|
||||
}
|
||||
|
||||
} // namespace V1_1
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_DLI_V1_1_VENDOR_INTERFACE_H
|
||||
#define OHOS_HDI_NEARLINK_DLI_V1_1_VENDOR_INTERFACE_H
|
||||
|
||||
#include <functional>
|
||||
#include <shared_mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "singleton.h"
|
||||
|
||||
#include "dli_internal.h"
|
||||
#include "dli_protocol.h"
|
||||
#include "dli_watcher.h"
|
||||
#include "ohos_sle_vendor_lib.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
namespace V1_1 {
|
||||
class VendorInterface : public DelayedSingleton<VendorInterface>,
|
||||
public std::enable_shared_from_this<VendorInterface> {
|
||||
public:
|
||||
using InitializeCompleteCallback = std::function<void(bool isSuccess)>;
|
||||
using ReceiveDataCallback = Dli::DliProtocol::DliDataCallback;
|
||||
struct ReceiveCallback {
|
||||
ReceiveDataCallback onAcbReceive;
|
||||
ReceiveDataCallback onIcbReceive;
|
||||
ReceiveDataCallback onEventReceive;
|
||||
};
|
||||
|
||||
bool Initialize(InitializeCompleteCallback initializeCompleteCallback, const ReceiveCallback &receiveCallback);
|
||||
void CleanUp();
|
||||
size_t SendPacket(const std::vector<uint8_t> &packet);
|
||||
|
||||
private:
|
||||
// callback function
|
||||
void OnEventReceived(const std::vector<uint8_t> &data);
|
||||
void OnAcbReceived(const std::vector<uint8_t> &data);
|
||||
void OnIcbReceived(const std::vector<uint8_t> &data);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
std::shared_mutex vendorMutex_;
|
||||
std::weak_ptr<VendorInterface> vendorInterfaceWeak_;
|
||||
|
||||
DECLARE_DELAYED_SINGLETON(VendorInterface);
|
||||
DISALLOW_COPY_AND_MOVE(VendorInterface);
|
||||
};
|
||||
} // namespace V1_1
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_Nearlink_DLI_V1_1_VENDOR_INTERFACE_H */
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef OHOS_HDI_NEARLINK_HCI_V1_1_REMOTE_DEATH_RECIPIENT_H
|
||||
#define OHOS_HDI_NEARLINK_HCI_V1_1_REMOTE_DEATH_RECIPIENT_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "iremote_object.h"
|
||||
#include "refbase.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Dli {
|
||||
namespace V1_1 {
|
||||
class RemoteDeathRecipient : public IRemoteObject::DeathRecipient {
|
||||
public:
|
||||
explicit RemoteDeathRecipient(std::function<void(const wptr<IRemoteObject> &)> callback)
|
||||
{
|
||||
callback_ = callback;
|
||||
}
|
||||
~RemoteDeathRecipient()
|
||||
{
|
||||
callback_ = nullptr;
|
||||
}
|
||||
|
||||
void OnRemoteDied(const wptr<IRemoteObject> &object)
|
||||
{
|
||||
if (callback_ != nullptr) {
|
||||
callback_(object);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(const wptr<IRemoteObject> &)> callback_;
|
||||
};
|
||||
} // namespace V1_1
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // OHOS
|
||||
|
||||
#endif // OHOS_HDI_NEARLINK_HCI_V1_1_REMOTE_DEATH_RECIPIENT_H
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <hdf_base.h>
|
||||
#include <hdf_device_desc.h>
|
||||
#include <hdf_log.h>
|
||||
#include <hdf_sbuf_ipc.h>
|
||||
#include "v1_1/sle_hci_interface_stub.h"
|
||||
|
||||
#define HDF_LOG_TAG sle_dli_interface_driver
|
||||
|
||||
using namespace OHOS::HDI::Nearlink::Hci::V1_1;
|
||||
|
||||
struct HdfSleDliInterfaceHost {
|
||||
struct IDeviceIoService ioService;
|
||||
OHOS::sptr<OHOS::IRemoteObject> stub;
|
||||
HdfSleDliInterfaceHost()
|
||||
{
|
||||
ioService.object.objectId = 0;
|
||||
ioService.Open = nullptr;
|
||||
ioService.Release = nullptr;
|
||||
ioService.Dispatch = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static int32_t SleDliInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
|
||||
struct HdfSBuf *reply)
|
||||
{
|
||||
auto *hdfSleDliInterfaceHost = CONTAINER_OF(client->device->service, struct HdfSleDliInterfaceHost, ioService);
|
||||
|
||||
OHOS::MessageParcel *dataParcel = nullptr;
|
||||
OHOS::MessageParcel *replyParcel = nullptr;
|
||||
OHOS::MessageOption option;
|
||||
|
||||
if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
|
||||
HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__);
|
||||
return HDF_ERR_INVALID_PARAM;
|
||||
}
|
||||
if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
|
||||
HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__);
|
||||
return HDF_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return hdfSleDliInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
|
||||
}
|
||||
|
||||
static int HdfSleDliInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
|
||||
{
|
||||
HDF_LOGI("%{public}s: driver init start", __func__);
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
static int HdfSleDliInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
|
||||
{
|
||||
HDF_LOGI("%{public}s: driver bind start", __func__);
|
||||
auto *hdfSleDliInterfaceHost = new (std::nothrow) HdfSleDliInterfaceHost;
|
||||
if (hdfSleDliInterfaceHost == nullptr) {
|
||||
HDF_LOGE("%{public}s: failed to create create HdfSleDliInterfaceHost object", __func__);
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
|
||||
hdfSleDliInterfaceHost->ioService.Dispatch = SleDliInterfaceDriverDispatch;
|
||||
hdfSleDliInterfaceHost->ioService.Open = NULL;
|
||||
hdfSleDliInterfaceHost->ioService.Release = NULL;
|
||||
|
||||
auto serviceImpl = OHOS::HDI::Nearlink::Hci::V1_1::ISleHciInterface::Get(true);
|
||||
if (serviceImpl == nullptr) {
|
||||
HDF_LOGE("%{public}s: failed to get of implement service", __func__);
|
||||
delete hdfSleDliInterfaceHost;
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
|
||||
hdfSleDliInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
|
||||
OHOS::HDI::Nearlink::Hci::V1_1::ISleHciInterface::GetDescriptor());
|
||||
if (hdfSleDliInterfaceHost->stub == nullptr) {
|
||||
HDF_LOGE("%{public}s: failed to get stub object", __func__);
|
||||
delete hdfSleDliInterfaceHost;
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
|
||||
deviceObject->service = &hdfSleDliInterfaceHost->ioService;
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
static void HdfSleDliInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
|
||||
{
|
||||
HDF_LOGI("%{public}s: driver release start", __func__);
|
||||
if (deviceObject->service == nullptr) {
|
||||
HDF_LOGE("HdfSleDliInterfaceDriverRelease not initted");
|
||||
return;
|
||||
}
|
||||
|
||||
auto *hdfSleDliInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfSleDliInterfaceHost, ioService);
|
||||
if (hdfSleDliInterfaceHost != nullptr) {
|
||||
delete hdfSleDliInterfaceHost;
|
||||
}
|
||||
}
|
||||
|
||||
struct HdfDriverEntry g_sledliinterfaceDriverEntry = {
|
||||
.moduleVersion = 1,
|
||||
.moduleName = "nearlink_dli",
|
||||
.Bind = HdfSleDliInterfaceDriverBind,
|
||||
.Init = HdfSleDliInterfaceDriverInit,
|
||||
.Release = HdfSleDliInterfaceDriverRelease,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
HDF_INIT(g_sledliinterfaceDriverEntry);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "sle_hci_interface_impl.h"
|
||||
#include <unistd.h>
|
||||
#include <hdf_base.h>
|
||||
#include "nearlink_hdf_log.h"
|
||||
#include <iproxy_broker.h>
|
||||
#include "vendor_interface.h"
|
||||
#include "sle_hal_constant.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Hci {
|
||||
namespace V1_1 {
|
||||
using VendorInterface = OHOS::HDI::Nearlink::Dli::V1_1::VendorInterface;
|
||||
using DliPacketType = OHOS::HDI::Nearlink::Dli::DliPacketType;
|
||||
thread_local bool SleHciInterfaceImpl::isThreadPromoted = false;
|
||||
using namespace OHOS::HDI::Nearlink::Dli;
|
||||
|
||||
|
||||
extern "C" ISleHciInterface *SleHciInterfaceImplGetInstance(void)
|
||||
{
|
||||
return new (std::nothrow) SleHciInterfaceImpl();
|
||||
}
|
||||
|
||||
SleHciInterfaceImpl::SleHciInterfaceImpl()
|
||||
{
|
||||
remoteDeathRecipient_ =
|
||||
new RemoteDeathRecipient(std::bind(&SleHciInterfaceImpl::OnRemoteDied, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
SleHciInterfaceImpl::~SleHciInterfaceImpl()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dliCallbackMutex_);
|
||||
if (callbacks_ != nullptr) {
|
||||
RemoveDliDeathRecipient(callbacks_);
|
||||
callbacks_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t SleHciInterfaceImpl::SleHalInit(const sptr<OHOS::HDI::Nearlink::Hci::V1_0::ISleHciCallback>& callbackObj)
|
||||
{
|
||||
HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__);
|
||||
if (callbackObj == nullptr) {
|
||||
HDF_LOGE("SleHciInterfaceImpl %{public}s callbackObj null", __func__);
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
|
||||
VendorInterface::ReceiveCallback callback = {
|
||||
.onAcbReceive =
|
||||
[callbackObj](
|
||||
const std::vector<uint8_t> &packet) { callbackObj->hciPacketReceived(SleType::ACB_DATA, packet); },
|
||||
.onIcbReceive =
|
||||
[callbackObj](
|
||||
const std::vector<uint8_t> &packet) { callbackObj->hciPacketReceived(SleType::ICB_DATA, packet); },
|
||||
.onEventReceive =
|
||||
[callbackObj](
|
||||
const std::vector<uint8_t> &packet) { callbackObj->hciPacketReceived(SleType::HCI_EVENT, packet); },
|
||||
};
|
||||
|
||||
bool result = VendorInterface::GetInstance()->Initialize(
|
||||
[callbackObj](bool status) {
|
||||
callbackObj->initializationComplete(status ? SleStatus::SUCCESS : SleStatus::INITIALIZATION_ERROR);
|
||||
}, callback);
|
||||
if (result) {
|
||||
std::lock_guard<std::mutex> lock(dliCallbackMutex_);
|
||||
callbacks_ = callbackObj;
|
||||
AddDliDeathRecipient(callbacks_);
|
||||
}
|
||||
return result ? HDF_SUCCESS : HDF_FAILURE;
|
||||
}
|
||||
|
||||
int32_t SleHciInterfaceImpl::SleSendHciPacket(const std::vector<uint8_t>& data)
|
||||
{
|
||||
HDF_LOGD("SleHciInterfaceImpl %{public}s", __func__);
|
||||
if (data.empty()) {
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
SetRTSchedule();
|
||||
|
||||
size_t result = VendorInterface::GetInstance()->SendPacket(data);
|
||||
return result ? HDF_SUCCESS : HDF_FAILURE;
|
||||
}
|
||||
|
||||
int32_t SleHciInterfaceImpl::CheckOnBoardState(bool& result)
|
||||
{
|
||||
HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__);
|
||||
result = true;
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t SleHciInterfaceImpl::Close()
|
||||
{
|
||||
HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dliCallbackMutex_);
|
||||
if (callbacks_ != nullptr) {
|
||||
RemoveDliDeathRecipient(callbacks_);
|
||||
callbacks_ = nullptr;
|
||||
}
|
||||
}
|
||||
VendorInterface::GetInstance()->CleanUp();
|
||||
VendorInterface::DestroyInstance();
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
void SleHciInterfaceImpl::OnRemoteDied(const wptr<IRemoteObject> &object)
|
||||
{
|
||||
HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dliCallbackMutex_);
|
||||
callbacks_ = nullptr;
|
||||
}
|
||||
VendorInterface::GetInstance()->CleanUp();
|
||||
VendorInterface::DestroyInstance();
|
||||
}
|
||||
|
||||
int32_t SleHciInterfaceImpl::AddDliDeathRecipient(const sptr<ISleHciCallback>& callbackObj)
|
||||
{
|
||||
HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__);
|
||||
const sptr<IRemoteObject>& remote = OHOS::HDI::hdi_objcast<ISleHciCallback>(callbackObj);
|
||||
if (!remote) {
|
||||
HDF_LOGE("remote is nullptr");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
bool result = remote->AddDeathRecipient(remoteDeathRecipient_);
|
||||
if (!result) {
|
||||
HDF_LOGE("SleHciInterfaceImpl AddDeathRecipient fail");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t SleHciInterfaceImpl::RemoveDliDeathRecipient(const sptr<ISleHciCallback>& callbackObj)
|
||||
{
|
||||
HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__);
|
||||
const sptr<IRemoteObject>& remote = OHOS::HDI::hdi_objcast<ISleHciCallback>(callbackObj);
|
||||
if (!remote) {
|
||||
HDF_LOGE("remote is nullptr");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
bool result = remote->RemoveDeathRecipient(remoteDeathRecipient_);
|
||||
if (!result) {
|
||||
HDF_LOGE("SleHciInterfaceImpl RemoveDeathRecipient fail");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
void SleHciInterfaceImpl::SetRTSchedule()
|
||||
{
|
||||
if (isThreadPromoted) {
|
||||
return;
|
||||
}
|
||||
pid_t tid = gettid();
|
||||
struct sched_param rtParams = {.sched_priority = SLE_THREAD_PRIORITY};
|
||||
int rc = sched_setscheduler(tid, SCHED_FIFO, &rtParams);
|
||||
isThreadPromoted = (rc != 0) ? false : true;
|
||||
}
|
||||
} // V1_1
|
||||
} // Hci
|
||||
} // Nearlink
|
||||
} // HDI
|
||||
} // OHOS
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef OHOS_HDI_NEARLINK_DLI_V1_1_SLEDLIINTERFACEIMPL_H
|
||||
#define OHOS_HDI_NEARLINK_DLI_V1_1_SLEDLIINTERFACEIMPL_H
|
||||
|
||||
#include "v1_1/isle_hci_interface.h"
|
||||
#include "v1_0/isle_hci_callback.h"
|
||||
#include "remote_death_recipient.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Hci {
|
||||
namespace V1_1 {
|
||||
using namespace OHOS::HDI::Nearlink::Dli::V1_1;
|
||||
class SleHciInterfaceImpl : public OHOS::HDI::Nearlink::Hci::V1_1::ISleHciInterface {
|
||||
public:
|
||||
SleHciInterfaceImpl();
|
||||
virtual ~SleHciInterfaceImpl();
|
||||
|
||||
int32_t SleHalInit(const sptr<OHOS::HDI::Nearlink::Hci::V1_0::ISleHciCallback>& callbackObj) override;
|
||||
|
||||
int32_t SleSendHciPacket(const std::vector<uint8_t>& data) override;
|
||||
|
||||
int32_t Close() override;
|
||||
|
||||
int32_t CheckOnBoardState(bool& result) override;
|
||||
private:
|
||||
void OnRemoteDied(const wptr<IRemoteObject> &object);
|
||||
sptr<ISleHciCallback> callbacks_ = nullptr;
|
||||
sptr<RemoteDeathRecipient> remoteDeathRecipient_ = nullptr;
|
||||
int32_t AddDliDeathRecipient(const sptr<ISleHciCallback>& callbackObj);
|
||||
int32_t RemoveDliDeathRecipient(const sptr<ISleHciCallback>& callbackObj);
|
||||
void SetRTSchedule();
|
||||
std::mutex dliCallbackMutex_;
|
||||
thread_local static bool isThreadPromoted;
|
||||
};
|
||||
} // V1_1
|
||||
} // Hci
|
||||
} // Nearlink
|
||||
} // HDI
|
||||
} // OHOS
|
||||
|
||||
#endif // OHOS_HDI_NEARLINK_DLI_V1_1_SleHciInterfaceImplE_H
|
||||
@@ -0,0 +1,44 @@
|
||||
# Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import("//build/test.gni")
|
||||
|
||||
group("nearlink_hdi_test") {
|
||||
testonly = true
|
||||
deps = [
|
||||
":NearlinkHdiTest",
|
||||
]
|
||||
}
|
||||
|
||||
ohos_unittest("NearlinkHdiTest") {
|
||||
module_out_path = "drivers_peripheral_nearlink/drivers_peripheral_nearlink/"
|
||||
|
||||
sources = [
|
||||
"nearlink_hdi_test.cpp",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"../dli_service",
|
||||
]
|
||||
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"hdf_core:libhdf_host",
|
||||
"hdf_core:libhdf_utils",
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_single",
|
||||
"drivers_interface_nearlink:libnearlink_hci_proxy_1.0",
|
||||
"drivers_interface_nearlink:libnearlink_hci_proxy_1.1",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <hdf_log.h>
|
||||
#include <vector>
|
||||
#include "v1_1/isle_hci_interface.h"
|
||||
#include "v1_0/isle_hci_callback.h"
|
||||
|
||||
using namespace testing::ext;
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace Hci {
|
||||
namespace V1_1 {
|
||||
|
||||
sptr<ISleHciInterface> nearlinkDliInterface = nullptr;
|
||||
|
||||
class NearlinkDliHdiTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase(void);
|
||||
static void TearDownTestCase(void);
|
||||
void SetUp();
|
||||
void TearDown();
|
||||
};
|
||||
|
||||
|
||||
class NearlinkDliCallbacksForTest : public ISleHciCallback {
|
||||
public:
|
||||
NearlinkDliCallbacksForTest()
|
||||
{}
|
||||
~NearlinkDliCallbacksForTest()
|
||||
{}
|
||||
|
||||
int32_t initializationComplete(SleStatus status)
|
||||
{
|
||||
GTEST_LOG_(INFO) << "NeearlinkDliCallbacksForTest::initializationComplete called";
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t hciPacketReceived(uint32_t type, const std::vector<uint8_t> &data)
|
||||
{
|
||||
GTEST_LOG_(INFO) << "NeearlinkDliCallbacksForTest::hciPacketReceived called";
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
void NearlinkDliHdiTest::SetUpTestCase(void)
|
||||
{
|
||||
// input testsuit setup step,setup invoked before all testcases
|
||||
nearlinkDliInterface = OHOS::HDI::Nearlink::Hci::V1_1::ISleHciInterface::Get(true);
|
||||
if (nearlinkDliInterface == nullptr) {
|
||||
HDF_LOGE("nearlinkDliHdiTest nearlinkDliInterface is nullptr\n");
|
||||
}
|
||||
}
|
||||
|
||||
void NearlinkDliHdiTest::TearDownTestCase(void)
|
||||
{
|
||||
// input testsuit teardown step,teardown invoked after all testcases
|
||||
}
|
||||
|
||||
void NearlinkDliHdiTest::SetUp(void)
|
||||
{
|
||||
// input testcase setup step,setup invoked before each testcases
|
||||
}
|
||||
|
||||
void NearlinkDliHdiTest::TearDown(void)
|
||||
{
|
||||
// input testcase teardown step,teardown invoked after each testcases
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: HDI_nearlinkDliInterface_001_SleHalInitTest
|
||||
* @tc.desc: Test nearlinkDliInterface SleHalInit.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(NearlinkDliHdiTest, HDI_nearlinkDliInterface_001_SleHalInitTest, TestSize.Level1)
|
||||
{
|
||||
sptr<NearlinkDliCallbacksForTest> callback_ = new NearlinkDliCallbacksForTest();
|
||||
int ret = nearlinkDliInterface->SleHalInit(callback_);
|
||||
EXPECT_EQ(-1, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: HDI_nearlinkDliInterface_002_SleSendHciPacketTest
|
||||
* @tc.desc: Test nearlinkDliInterface SleSendHciPacket.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(NearlinkDliHdiTest, HDI_nearlinkDliInterface_002_SleSendHciPacketTest, TestSize.Level1)
|
||||
{
|
||||
sptr<NearlinkDliCallbacksForTest> callback_ = new NearlinkDliCallbacksForTest();
|
||||
int ret = nearlinkDliInterface->SleHalInit(callback_);
|
||||
EXPECT_EQ(-1, ret);
|
||||
std::vector<uint8_t> sleHciTestData = {0xA1, 0x07, 0x10, 0x02, 0x00, 0x00, 0x00};
|
||||
ret = nearlinkDliInterface->SleSendHciPacket(sleHciTestData);
|
||||
EXPECT_EQ(-1, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: HDI_nearlinkDliInterface_003_SleCloseTest
|
||||
* @tc.desc: Test nearlinkDliInterface SleClose.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(NearlinkDliHdiTest, HDI_nearlinkDliInterface_003_SleCloseTest, TestSize.Level1)
|
||||
{
|
||||
sptr<NearlinkDliCallbacksForTest> callback_ = new NearlinkDliCallbacksForTest();
|
||||
int ret = nearlinkDliInterface->SleHalInit(callback_);
|
||||
EXPECT_EQ(-1, ret);
|
||||
ret = nearlinkDliInterface->Close();
|
||||
EXPECT_EQ(0, ret);
|
||||
}
|
||||
|
||||
} // V1_1
|
||||
} // Hci
|
||||
} // Nearlink
|
||||
} // HDI
|
||||
} // OHOS
|
||||
@@ -0,0 +1,17 @@
|
||||
# Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
declare_args() {
|
||||
drivers_peripheral_nearlink_feature_support_send_disable_hci = false
|
||||
drivers_peripheral_nearlink_reload_address = false
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//build/ohos.gni")
|
||||
|
||||
if (defined(ohos_lite)) {
|
||||
group("off_find_entry") {
|
||||
deps = []
|
||||
}
|
||||
} else {
|
||||
group("off_find_entry") {
|
||||
deps = [
|
||||
"hdi_service:hdf_off_find_service",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
# Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import("//build/config/components/hdi/hdi.gni")
|
||||
import("//out/products_ext/hmos_ext_var.gni")
|
||||
import("../../drivers_peripheral_nearlink.gni")
|
||||
|
||||
ohos_shared_library("liboff_find_interface_service_1.0") {
|
||||
sanitize = {
|
||||
cfi = true # Enable/disable control flow integrity detection
|
||||
boundary_sanitize = true # Enable boundary san detection
|
||||
cfi_cross_dso = true # Cross-SO CFI Checks
|
||||
integer_overflow = true # Enable integer overflow detection
|
||||
ubsan = true # Enable some Ubsan options
|
||||
debug = false
|
||||
}
|
||||
branch_protector_ret = "pac_ret"
|
||||
|
||||
cflags = [
|
||||
"-Os",
|
||||
"-fdata-sections",
|
||||
"-ffunction-sections",
|
||||
"-fno-unwind-tables",
|
||||
"-fno-asynchronous-unwind-tables",
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
"-fPIC",
|
||||
"-fno-common",
|
||||
"-fstack-protector-strong",
|
||||
"-fvisibility-inlines-hidden",
|
||||
"-flto",
|
||||
]
|
||||
cflags_cc = cflags
|
||||
ldflags = [
|
||||
"-Wl,--as-needed",
|
||||
"-Wl,--gc-sections",
|
||||
"-Wl,--no-whole-archive",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
".",
|
||||
"implement",
|
||||
]
|
||||
|
||||
sources = [
|
||||
"off_find_interface_impl.cpp",
|
||||
"implement/h4_protocol.cpp",
|
||||
"implement/dli_protocol.cpp",
|
||||
"implement/dli_watcher.cpp",
|
||||
"implement/vendor_interface.cpp",
|
||||
"implement/thread_util.cpp",
|
||||
]
|
||||
|
||||
defines = []
|
||||
|
||||
if (drivers_peripheral_nearlink_feature_support_send_disable_hci) {
|
||||
defines += [ "SEND_DISABLE_OFF_FIND_DLI" ]
|
||||
}
|
||||
|
||||
if (is_standard_system) {
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"drivers_interface_nearlink:off_find_idl_headers",
|
||||
"hdf_core:libhdf_host",
|
||||
"hdf_core:libhdf_utils",
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_core",
|
||||
"ffrt:libffrt",
|
||||
"init:libbegetutil"
|
||||
]
|
||||
} else {
|
||||
external_deps = [
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_core",
|
||||
]
|
||||
}
|
||||
|
||||
install_images = [ chipset_base_dir ]
|
||||
subsystem_name = "hdf"
|
||||
part_name = "drivers_peripheral_nearlink"
|
||||
}
|
||||
|
||||
ohos_shared_library("liboff_find_hdi_driver") {
|
||||
sanitize = {
|
||||
cfi = true # Enable/disable control flow integrity detection
|
||||
boundary_sanitize = true # Enable boundary san detection
|
||||
cfi_cross_dso = true # Cross-SO CFI Checks
|
||||
integer_overflow = true # Enable integer overflow detection
|
||||
ubsan = true # Enable some Ubsan options
|
||||
debug = false
|
||||
}
|
||||
branch_protector_ret = "pac_ret"
|
||||
|
||||
cflags = [
|
||||
"-Os",
|
||||
"-fdata-sections",
|
||||
"-ffunction-sections",
|
||||
"-fno-unwind-tables",
|
||||
"-fno-asynchronous-unwind-tables",
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
"-fPIC",
|
||||
"-fno-common",
|
||||
"-fstack-protector-strong",
|
||||
"-fvisibility-inlines-hidden",
|
||||
"-flto",
|
||||
]
|
||||
cflags_cc = cflags
|
||||
ldflags = [
|
||||
"-Wl,--as-needed",
|
||||
"-Wl,--gc-sections",
|
||||
"-Wl,--no-whole-archive",
|
||||
]
|
||||
|
||||
include_dirs = [ "." ]
|
||||
|
||||
sources = [ "off_find_interface_driver.cpp" ]
|
||||
|
||||
if (is_standard_system) {
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"hdf_core:libhdf_host",
|
||||
"hdf_core:libhdf_ipc_adapter",
|
||||
"hdf_core:libhdf_utils",
|
||||
"hdf_core:libhdi",
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_single",
|
||||
]
|
||||
} else {
|
||||
external_deps = [
|
||||
"hilog:libhilog",
|
||||
"ipc:ipc_single",
|
||||
]
|
||||
}
|
||||
|
||||
external_deps += [ "drivers_interface_nearlink:liboff_find_stub_1.0" ]
|
||||
|
||||
shlib_type = "hdi"
|
||||
install_images = [ chipset_base_dir ]
|
||||
subsystem_name = "hdf"
|
||||
part_name = "drivers_peripheral_nearlink"
|
||||
}
|
||||
|
||||
group("hdf_off_find_service") {
|
||||
deps = [
|
||||
":liboff_find_hdi_driver",
|
||||
":liboff_find_interface_service_1.0",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_DLI_INTERNAL_H
|
||||
#define OHOS_HDI_NEARLINK_DLI_INTERNAL_H
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
typedef enum {
|
||||
DLI_PACKET_TYPE_UNKNOWN = 0,
|
||||
DLI_PACKET_TYPE_SLE_CMD = 0xA1,
|
||||
DLI_PACKET_TYPE_SLE_EVENT = 0xA2,
|
||||
DLI_PACKET_TYPE_MAX,
|
||||
} DliPacketType;
|
||||
|
||||
struct PacketHeader {
|
||||
uint8_t headerSize;
|
||||
uint8_t dataLengthOffset;
|
||||
uint8_t dataLengthSize;
|
||||
};
|
||||
|
||||
// opcode (DLI_SLE_Cmd_Complete_Evt opcode)
|
||||
const uint16_t SLE_DLI_COMMAND_COMPLETE_EVENT = 0x0002;
|
||||
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_NEARLINK_DLI_INTERNAL_H */
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include "off_find_log.h"
|
||||
#include "dli_protocol.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
const PacketHeader DliProtocol::header_[DLI_PACKET_TYPE_MAX] = {
|
||||
{.headerSize = 0, .dataLengthOffset = 0, .dataLengthSize = 0}, /* 0 */
|
||||
{.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 1 */
|
||||
{.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 4 */
|
||||
};
|
||||
|
||||
const PacketHeader &DliProtocol::GetPacketHeaderInfo(DliPacketType packetType)
|
||||
{
|
||||
if (packetType >= DLI_PACKET_TYPE_MAX) {
|
||||
return header_[DLI_PACKET_TYPE_UNKNOWN];
|
||||
}
|
||||
return header_[DliProtocol::TypeConvert(packetType)];
|
||||
}
|
||||
|
||||
ssize_t DliProtocol::Read(int fd, uint8_t *data, size_t length)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
char buf[bufsize] = {0};
|
||||
ssize_t ret = TEMP_FAILURE_RETRY(read(fd, data, length));
|
||||
if (ret == -1) {
|
||||
strerror_r(errno, buf, sizeof(buf));
|
||||
HDF_LOGE("read failed err:%s", buf);
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t DliProtocol::Write(int fd, const uint8_t *data, size_t length)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
char buf[bufsize] = {0};
|
||||
ssize_t ret = 0;
|
||||
do {
|
||||
ret = TEMP_FAILURE_RETRY(write(fd, data, length));
|
||||
} while (ret == -1 && errno == EAGAIN);
|
||||
|
||||
if (ret == -1) {
|
||||
strerror_r(errno, buf, sizeof(buf));
|
||||
HDF_LOGE("write failed err:%s", buf);
|
||||
} else if (static_cast<size_t>(ret) != length) {
|
||||
HDF_LOGE("write data %zd less than %zu.", ret, length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t DliProtocol::TypeConvert(DliPacketType packetType)
|
||||
{
|
||||
switch (packetType) {
|
||||
case DLI_PACKET_TYPE_SLE_EVENT:
|
||||
return static_cast<uint8_t>(DLI_PACKET_TYPE_SLE_EVENT) & 0x0F;
|
||||
default:
|
||||
HDF_LOGE("type convert error.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_DLI_PROTOCOL_H
|
||||
#define OHOS_HDI_NEARLINK_DLI_PROTOCOL_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
#include <functional>
|
||||
#include "dli_internal.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
class DliProtocol {
|
||||
public:
|
||||
using DliDataCallback = std::function<void(const std::vector<uint8_t> &data)>;
|
||||
|
||||
DliProtocol() = default;
|
||||
virtual ~DliProtocol() = default;
|
||||
|
||||
virtual ssize_t SendPacket(const std::vector<uint8_t> &packetData) = 0;
|
||||
|
||||
const PacketHeader& GetPacketHeaderInfo(DliPacketType packetType);
|
||||
|
||||
protected:
|
||||
static ssize_t Read(int fd, uint8_t *data, size_t length);
|
||||
static ssize_t Write(int fd, const uint8_t *data, size_t length);
|
||||
static uint8_t TypeConvert(DliPacketType packetType);
|
||||
static const PacketHeader header_[DLI_PACKET_TYPE_MAX];
|
||||
};
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_NEARLINK_DLI_PROTOCOL_H */
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/syscall.h>
|
||||
#include "off_find_log.h"
|
||||
#include "off_find_hdi_constant.h"
|
||||
#include "dli_watcher.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
DliWatcher::DliWatcher()
|
||||
{}
|
||||
|
||||
DliWatcher::~DliWatcher()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool DliWatcher::AddFdToWatcher(int fd, DliDataCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fdsMutex_);
|
||||
fds_[fd] = callback;
|
||||
ThreadWakeup();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DliWatcher::RemoveFdToWatcher(int fd)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fdsMutex_);
|
||||
fds_.erase(fd);
|
||||
ThreadWakeup();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DliWatcher::SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback)
|
||||
{
|
||||
std::chrono::seconds seconds = std::chrono::duration_cast<std::chrono::seconds>(timeout);
|
||||
std::lock_guard<std::mutex> lock(timeoutMutex_);
|
||||
timeoutTimer_.tv_sec = seconds.count();
|
||||
timeoutTimer_.tv_usec = (timeout - seconds).count();
|
||||
timeoutCallback_ = callback;
|
||||
ThreadWakeup();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DliWatcher::Start()
|
||||
{
|
||||
if (running_.exchange(true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
if (pipe(wakeupPipe_) != 0) {
|
||||
HDF_LOGE("DliWatcher create pipe failed.");
|
||||
running_.exchange(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
thread_ = std::thread(std::bind(&DliWatcher::WatcherThread, this));
|
||||
if (!thread_.joinable()) {
|
||||
HDF_LOGE("thread is not joinable.");
|
||||
running_.exchange(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
int policy = SLE_THREAD_POLICY;
|
||||
sched_param params = {.sched_priority = SLE_THREAD_PRIORITY};
|
||||
if (pthread_setschedparam(thread_.native_handle(), policy, ¶ms) != 0) {
|
||||
HDF_LOGW("pthread_setschedparam failed tid[%lu] policy[%d]", thread_.native_handle(), policy);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DliWatcher::Stop()
|
||||
{
|
||||
if (!running_.exchange(false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadWakeup();
|
||||
thread_.join();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
close(wakeupPipe_[0]);
|
||||
close(wakeupPipe_[1]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DliWatcher::CheckFdReady(std::map<int, DliDataCallback>& fds, fd_set &readFds)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fdsMutex_);
|
||||
for (auto &&fd : fds_) {
|
||||
if (FD_ISSET(fd.first, &readFds)) {
|
||||
fd.second(fd.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DliWatcher::WatcherThread()
|
||||
{
|
||||
fd_set readFds;
|
||||
int nfds;
|
||||
timeval *timeout = nullptr;
|
||||
|
||||
while (running_) {
|
||||
FD_ZERO(&readFds);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
FD_SET(wakeupPipe_[0], &readFds);
|
||||
nfds = wakeupPipe_[0];
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fdsMutex_);
|
||||
for (auto &&fd : fds_) {
|
||||
FD_SET(fd.first, &readFds);
|
||||
nfds = std::max(fd.first, nfds);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(timeoutMutex_);
|
||||
if (timeoutTimer_.tv_sec == 0 && timeoutTimer_.tv_usec == 0) {
|
||||
timeout = nullptr;
|
||||
} else {
|
||||
timeout = &timeoutTimer_;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = select(nfds + 1, &readFds, nullptr, nullptr, timeout);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
} else if (ret == 0) {
|
||||
TimeoutCallback callback;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(timeoutMutex_);
|
||||
callback = timeoutCallback_;
|
||||
}
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
if (FD_ISSET(wakeupPipe_[0], &readFds)) {
|
||||
uint8_t buff = 0;
|
||||
TEMP_FAILURE_RETRY(read(wakeupPipe_[0], &buff, sizeof(buff)));
|
||||
}
|
||||
}
|
||||
CheckFdReady(fds_, readFds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DliWatcher::ThreadWakeup()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(wakeupPipeMutex_);
|
||||
uint8_t buff = 0;
|
||||
TEMP_FAILURE_RETRY(write(wakeupPipe_[1], &buff, sizeof(buff)));
|
||||
}
|
||||
} // namespace Dli
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_HCI_WATCHER_H
|
||||
#define OHOS_HDI_NEARLINK_HCI_WATCHER_H
|
||||
|
||||
#include <atomic>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <sys/time.h>
|
||||
#include <thread>
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
class DliWatcher {
|
||||
public:
|
||||
using DliDataCallback = std::function<void(int fd)>;
|
||||
using TimeoutCallback = std::function<void()>;
|
||||
|
||||
DliWatcher();
|
||||
~DliWatcher();
|
||||
|
||||
bool AddFdToWatcher(int fd, DliDataCallback callback);
|
||||
bool RemoveFdToWatcher(int fd);
|
||||
bool SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback);
|
||||
bool Start();
|
||||
bool Stop();
|
||||
|
||||
private:
|
||||
void CheckFdReady(std::map<int, DliDataCallback>& fds, fd_set &readFds);
|
||||
void WatcherThread();
|
||||
void ThreadWakeup();
|
||||
|
||||
private:
|
||||
std::atomic_bool running_ = {false};
|
||||
std::map<int, DliDataCallback> fds_;
|
||||
std::mutex fdsMutex_;
|
||||
std::mutex wakeupPipeMutex_;
|
||||
int wakeupPipe_[2] = {0};
|
||||
timeval timeoutTimer_ = {};
|
||||
TimeoutCallback timeoutCallback_;
|
||||
std::mutex timeoutMutex_;
|
||||
std::thread thread_;
|
||||
};
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_NEARLINK_HCI_WATCHER_H */
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include "off_find_log.h"
|
||||
#include "h4_protocol.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
H4Protocol::H4Protocol(
|
||||
int fd, DliDataCallback onEventReceive)
|
||||
: dliFd_(fd), onEventReceive_(onEventReceive)
|
||||
{}
|
||||
|
||||
ssize_t H4Protocol::SendPacket(const std::vector<uint8_t> &packetData)
|
||||
{
|
||||
ssize_t writtenNumber = 0;
|
||||
ssize_t ret = 0;
|
||||
do {
|
||||
ret = Write(dliFd_, packetData.data() + writtenNumber, packetData.size() - writtenNumber);
|
||||
if (ret > 0) {
|
||||
writtenNumber += ret;
|
||||
} else if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
} while (static_cast<size_t>(writtenNumber) < packetData.size());
|
||||
return writtenNumber;
|
||||
}
|
||||
|
||||
static bool ReadLengthCheck(ssize_t readLen, char *buf, int fd)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
if (readLen < 0) {
|
||||
strerror_r(errno, buf, bufsize);
|
||||
HDF_LOGE("read fd[%d] err:%s", fd, buf);
|
||||
return false;
|
||||
} else if (readLen == 0) {
|
||||
HDF_LOGE("read fd[%d] readLen = 0.", fd);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void H4Protocol::ReadData(int fd)
|
||||
{
|
||||
const int bufsize = 256;
|
||||
char buf[bufsize] = {0};
|
||||
static uint8_t typeNo{0};
|
||||
ssize_t readLen = 0;
|
||||
if (dliPacket_.size() == 0) {
|
||||
readLen = Read(fd, &packetType_, sizeof(packetType_));
|
||||
if (readLen < 0) {
|
||||
HDF_LOGE("read fd[%d]", fd);
|
||||
return;
|
||||
} else if (readLen == 0) {
|
||||
HDF_LOGE("read fd[%d] readLen = 0.", fd);
|
||||
return;
|
||||
}
|
||||
typeNo = (packetType_) & 0x0F;
|
||||
if (packetType_ > DLI_PACKET_TYPE_UNKNOWN && packetType_ < DLI_PACKET_TYPE_MAX) {
|
||||
dliPacket_.resize(header_[typeNo].headerSize);
|
||||
}
|
||||
} else if (dliPacket_.size() == header_[typeNo].headerSize) {
|
||||
readLen = Read(fd, dliPacket_.data() + readLength_, dliPacket_.size() - readLength_);
|
||||
if (!ReadLengthCheck(readLen, buf, fd)) {
|
||||
return;
|
||||
}
|
||||
readLength_ += readLen;
|
||||
if (readLength_ == dliPacket_.size()) {
|
||||
size_t dataLen = 0;
|
||||
for (int ii = 0; ii < header_[typeNo].dataLengthSize; ii++) {
|
||||
dataLen += (dliPacket_[header_[typeNo].dataLengthOffset + ii] << (ii * 0x08));
|
||||
}
|
||||
dliPacket_.resize(dliPacket_.size() + dataLen);
|
||||
}
|
||||
} else {
|
||||
readLen = Read(fd, dliPacket_.data() + readLength_, dliPacket_.size() - readLength_);
|
||||
if (!ReadLengthCheck(readLen, buf, fd)) {
|
||||
return;
|
||||
}
|
||||
readLength_ += readLen;
|
||||
if (readLength_ == dliPacket_.size()) {
|
||||
PacketCallback();
|
||||
dliPacket_.clear();
|
||||
readLength_ = 0;
|
||||
typeNo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
H4Protocol::~H4Protocol() {}
|
||||
|
||||
void H4Protocol::PacketCallback()
|
||||
{
|
||||
switch (packetType_) {
|
||||
case DLI_PACKET_TYPE_SLE_EVENT:
|
||||
if (onEventReceive_) {
|
||||
onEventReceive_(dliPacket_);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
HDF_LOGE("PacketCallback type[%d] error.", packetType_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_HCI_H4_PROTOCOL_H
|
||||
#define OHOS_HDI_NEARLINK_HCI_H4_PROTOCOL_H
|
||||
|
||||
#include "dli_protocol.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
class H4Protocol : public DliProtocol {
|
||||
public:
|
||||
H4Protocol(int fd, DliDataCallback onEventReceive);
|
||||
|
||||
ssize_t SendPacket(const std::vector<uint8_t> &packetData) override;
|
||||
void ReadData(int fd);
|
||||
~H4Protocol() override;
|
||||
|
||||
private:
|
||||
void PacketCallback();
|
||||
|
||||
private:
|
||||
int dliFd_ = 0;
|
||||
DliDataCallback onEventReceive_;
|
||||
|
||||
uint8_t packetType_ = 0;
|
||||
|
||||
std::vector<uint8_t> dliPacket_;
|
||||
uint32_t readLength_ = 0;
|
||||
};
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
|
||||
#endif /* OHOS_HDI_NEARLINK_HCI_H4_PROTOCOL_H */
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_OFF_FIND_CONSTANT_H
|
||||
#define OHOS_HDI_NEARLINK_OFF_FIND_CONSTANT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
constexpr const char *OFF_FIND_VENDOR_NAME = "liboff_find_vendor";
|
||||
constexpr const char *SLE_OFF_FIND_CHIP_TYPE = "const.nearlink.off_find.slechiptype";
|
||||
constexpr const char *OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME = "NEARLINK_OFF_FIND_VENDOR_LIB_INTERFACE";
|
||||
constexpr const char *OFF_FIND_VENDOR_COMMON_NAME = "liboff_find_vendor_common_ext.z.so";
|
||||
constexpr const char *OFF_FIND_VENDOR_COMMON_INTERFACE_SYMBOL_NAME = "NEARLINK_OFF_FIND_VENDOR_COMMON_LIB_INTERFACE";
|
||||
constexpr int SLE_THREAD_POLICY = SCHED_RR;
|
||||
constexpr int SLE_THREAD_PRIORITY = 1;
|
||||
/**
|
||||
* Define OFF FIND MODEL ENABLE OR DISABLE RESULT.
|
||||
*/
|
||||
typedef enum {
|
||||
SUCCESS, // HCI Command channel
|
||||
INITIALIZATION_ERROR, // HCI Event channel
|
||||
} OffFindSwitchResult;
|
||||
|
||||
typedef enum {
|
||||
OFF_FIND_SUCCESS,
|
||||
OFF_FIND_FAIL,
|
||||
OFF_FIND_SYNC_FAIL,
|
||||
} OffFindErrorCode;
|
||||
|
||||
/**
|
||||
* Define POWER MODE CMD.
|
||||
*/
|
||||
typedef enum {
|
||||
CLEAR_RESERVED_POWER,
|
||||
SET_RESERVED_POWER
|
||||
} PmuPowerMode;
|
||||
|
||||
/**
|
||||
* Define off find capability.
|
||||
*/
|
||||
typedef enum {
|
||||
OF_SLE_ADV_ENABLE = 0x01,
|
||||
OF_SLE_RING_SUPPORT = 0X02,
|
||||
} OfSleFeatureFlag;
|
||||
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
|
||||
#endif /* OHOS_HDI_NEARLINK_OFF_FIND_CONSTANT_H */
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OFF_FIND_LOG_H
|
||||
#define OFF_FIND_LOG_H
|
||||
|
||||
#include <hdf_log.h>
|
||||
|
||||
#ifdef LOG_DOMAIN
|
||||
#undef LOG_DOMAIN
|
||||
#endif
|
||||
#define LOG_DOMAIN 0xD000154
|
||||
|
||||
#ifndef HDF_LOG_TAG
|
||||
#define HDF_LOG_TAG hdf_off_find
|
||||
#endif
|
||||
|
||||
#endif // OFF_FIND_LOG_H
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OFF_FIND_VENDOR_LIB_H
|
||||
#define OFF_FIND_VENDOR_LIB_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Define DLI channel descriptors array used in SLE_OP_DLI_CHANNEL_OPEN operation.
|
||||
*/
|
||||
typedef enum {
|
||||
DLI_CMD, // DLI Command channel
|
||||
DLI_EVT, // DLI Event channel
|
||||
DLI_MAX_CHANNEL // Total channels
|
||||
} DliChannelsT;
|
||||
|
||||
/**
|
||||
* SLE vendor lib cmd.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* Set Resvered Power for off find mode,it will be called when findnetwork enable.
|
||||
*/
|
||||
SLE_OP_RESERVERD_POWER_SET,
|
||||
/**
|
||||
* Establish dli channels. it will be called after SLE_OP_POWER_ON.
|
||||
* @param int (*)[DLI_MAX_CHANNEL].
|
||||
* @return fd count.
|
||||
*/
|
||||
SLE_OP_DLI_CHANNEL_OPEN,
|
||||
|
||||
/**
|
||||
* Close all the dli channels which is opened.
|
||||
*/
|
||||
SLE_OP_DLI_CHANNEL_CLOSE,
|
||||
/**
|
||||
* Set off find mode.
|
||||
* @param int *powerTime.
|
||||
*/
|
||||
SLE_OP_OFF_FIND_MODE_ENABLE,
|
||||
/**
|
||||
* Disable off find mode.
|
||||
*/
|
||||
SLE_OP_OFF_FIND_MODE_DISABLE,
|
||||
/**
|
||||
* Enable Leakage Prevention Mode mode.
|
||||
*/
|
||||
SLE_OP_OFF_FIND_POWER_PROTECT_ENABLE,
|
||||
} OffFindOpcodeT;
|
||||
|
||||
/**
|
||||
* Nearlink Host/Controller VENDOR Interface
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* Set to sizeof(sle_vndor_interface_t)
|
||||
*/
|
||||
size_t size;
|
||||
|
||||
/**
|
||||
* Caller will open the interface and pass in the callback routines
|
||||
* to the implementation of this interface.
|
||||
*/
|
||||
int (*init)(void);
|
||||
|
||||
/**
|
||||
* Vendor specific operations
|
||||
*/
|
||||
int (*op)(int opcode, void* param);
|
||||
|
||||
/**
|
||||
* Closes the interface
|
||||
*/
|
||||
void (*close)(void);
|
||||
} OffFindVendorInterfaceT;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
int (*modifyPowerProtect)(int powerTime, int power);
|
||||
bool (*isNeedWatcherStart)(std::string chipType);
|
||||
uint32_t (*getRegisterTimerDuration)(std::string chipType);
|
||||
void (*close)(void);
|
||||
} OffFindVendorCommInterfaceT;
|
||||
|
||||
typedef struct {
|
||||
uint16_t event;
|
||||
uint16_t len;
|
||||
uint16_t offset;
|
||||
uint16_t layerSpecific;
|
||||
uint8_t data[];
|
||||
} HC_SLE_HDR;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SLE_VENDOR_LIB_H */
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "thread_util.h"
|
||||
#include <mutex>
|
||||
#include "ffrt_inner.h"
|
||||
#include <hdf_log.h>
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
|
||||
void DoInDliThread(const ThreadUtilFunc &func)
|
||||
{
|
||||
ThreadUtil::GetInstance().PostTask(func);
|
||||
}
|
||||
|
||||
struct ThreadUtil::impl {
|
||||
class TaskQueue {
|
||||
public:
|
||||
explicit TaskQueue(const char *name) : queue_(name, ffrt::queue_attr().qos(ffrt::qos_user_interactive)) {}
|
||||
~TaskQueue() = default;
|
||||
|
||||
void PostTask(const ThreadUtilFunc &func);
|
||||
int GetQueueId(void);
|
||||
|
||||
private:
|
||||
ffrt::queue queue_;
|
||||
};
|
||||
|
||||
impl();
|
||||
~impl() = default;
|
||||
std::shared_ptr<TaskQueue> CreateTaskQueue();
|
||||
|
||||
std::shared_ptr<TaskQueue> taskQueue;
|
||||
};
|
||||
|
||||
ThreadUtil::impl::impl()
|
||||
{}
|
||||
|
||||
ThreadUtil::ThreadUtil() : pimpl(std::make_unique<impl>())
|
||||
{}
|
||||
|
||||
ThreadUtil::~ThreadUtil()
|
||||
{}
|
||||
|
||||
void ThreadUtil::impl::TaskQueue::PostTask(const ThreadUtilFunc &func)
|
||||
{
|
||||
queue_.submit(func);
|
||||
}
|
||||
|
||||
int ThreadUtil::impl::TaskQueue::GetQueueId(void)
|
||||
{
|
||||
int id = -1;
|
||||
auto handle = queue_.submit_h([&id]() {
|
||||
id = ffrt::get_queue_id();
|
||||
});
|
||||
queue_.wait(handle);
|
||||
return id;
|
||||
}
|
||||
|
||||
void ThreadUtil::PostTask(const ThreadUtilFunc &func)
|
||||
{
|
||||
std::lock_guard<ffrt::mutex> lock(taskQueueMutex_);
|
||||
std::shared_ptr<impl::TaskQueue> taskQueue = pimpl->taskQueue;
|
||||
if (taskQueue != nullptr) {
|
||||
taskQueue->PostTask(func);
|
||||
return;
|
||||
}
|
||||
// If the thread not found, create it.
|
||||
taskQueue = pimpl->CreateTaskQueue();
|
||||
// Execute the first task.
|
||||
if (taskQueue) {
|
||||
taskQueue->PostTask(func);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ThreadUtil::impl::TaskQueue> ThreadUtil::impl::CreateTaskQueue()
|
||||
{
|
||||
std::string threadName = "sle_hci";
|
||||
auto taskQueue_ = std::make_shared<TaskQueue>(threadName.c_str());
|
||||
|
||||
int queueId = taskQueue_->GetQueueId();
|
||||
HDF_LOGI("sle_ffrt_queue: queueId(%{public}d), name(%{public}s)", queueId, threadName.c_str());
|
||||
|
||||
taskQueue = taskQueue_;
|
||||
return taskQueue_;
|
||||
}
|
||||
|
||||
ThreadUtil &ThreadUtil::GetInstance()
|
||||
{
|
||||
static ThreadUtil instance;
|
||||
return instance;
|
||||
}
|
||||
} // namespace Nearlink
|
||||
} // namepsace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SLE_THREAD_UTIL_H
|
||||
#define SLE_THREAD_UTIL_H
|
||||
|
||||
#include <functional>
|
||||
#include "ffrt_inner.h"
|
||||
#include <hdf_log.h>
|
||||
#include "off_find_log.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
|
||||
using ThreadUtilFunc = std::function<void(void)>;
|
||||
|
||||
/**
|
||||
* @brief Post the task to the dli thread.
|
||||
* @param func The task to be executed.
|
||||
*/
|
||||
void DoInDliThread(const ThreadUtilFunc &func);
|
||||
|
||||
class ThreadUtil {
|
||||
public:
|
||||
void PostTask(const ThreadUtilFunc &func);
|
||||
static ThreadUtil &GetInstance();
|
||||
private:
|
||||
ThreadUtil();
|
||||
~ThreadUtil();
|
||||
|
||||
struct impl;
|
||||
std::unique_ptr<impl> pimpl;
|
||||
ffrt::mutex taskQueueMutex_ {};
|
||||
};
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
|
||||
#endif // SLE_THREAD_UTIL_H
|
||||
@@ -0,0 +1,620 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <chrono>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <securec.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <thread>
|
||||
|
||||
#include "off_find_log.h"
|
||||
#include "h4_protocol.h"
|
||||
#include "common_timer_errors.h"
|
||||
#include "parameters.h"
|
||||
#include "vendor_interface.h"
|
||||
#include "thread_util.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
namespace V1_0 {
|
||||
|
||||
// disable off find cmd
|
||||
#ifdef SEND_DISABLE_OFF_FIND_DLI
|
||||
constexpr uint8_t DLI_DISABLE_OFFFIDN_CMD = 0x16;
|
||||
constexpr uint8_t DLI_DISABLE_OFFFIDN_PARAM = 0x19;
|
||||
#endif
|
||||
|
||||
// Opcode
|
||||
constexpr uint16_t DLI_SWITCH_HOST = 0xFC92;
|
||||
constexpr uint16_t DLI_SET_POWER_OFF_PARAM = 0xFC91;
|
||||
|
||||
// Power off parm
|
||||
constexpr size_t DLI_PACKET_MIN_SIZE = 8;
|
||||
constexpr size_t DLI_PACKET_HEADER_SIZE = 5;
|
||||
constexpr size_t DLI_DATA_LEN_SIZE = 3;
|
||||
constexpr size_t DLI_ADVTIME_SIZE = 4;
|
||||
constexpr size_t ADV_FLAG_SIZE = 2; // ble and sle adv enable flag 1 on 0 off
|
||||
|
||||
// User and device Id len LIMIT
|
||||
constexpr size_t DEVICE_ID_LEN = 64;
|
||||
constexpr size_t USER_ID_LEN = 32;
|
||||
|
||||
// Advtising data len limit
|
||||
constexpr size_t ADV_KEY_LEN = 32;
|
||||
constexpr size_t ADV_CMAC_LEN = 2;
|
||||
|
||||
constexpr int OFFSET_EIGHT_BITS = 8;
|
||||
|
||||
// battery and correspond pwoerTime
|
||||
constexpr int BATTERY_ENTRY = 3;
|
||||
constexpr int BATTERY_HIGH_ENTRY = 10; // 关机七天可找电池阈值
|
||||
|
||||
constexpr int DEFAULT_CHIP_STEP = 1; // 默认芯片步长
|
||||
|
||||
constexpr int HIGH_POWER_TIME = 168; // 关机七天 7 day = 7*24h
|
||||
constexpr int UP_POWER_TIME = 48;
|
||||
constexpr int DOWN_POWER_TIME = 12;
|
||||
constexpr int AIR_OTA_POWER_TIME = 168; // 隔空升级 7 day = 7*24h
|
||||
constexpr size_t DEFAULT_ADV_DATA_LEN = 3; // 关机3d下发广播数组长度
|
||||
constexpr size_t SEVEN_DAYS_ADV_DATA_LEN = 8; // 关机7d下发广播数组长度
|
||||
// Data len dli position
|
||||
constexpr int THIRD_BYTE = 3;
|
||||
constexpr int FOURTH_BYTE = 4;
|
||||
constexpr int FIFTH_BYTE = 5;
|
||||
constexpr int SIXTH_BYTE = 6;
|
||||
constexpr int OFFSET_STATUS = 3;
|
||||
|
||||
// Data len limit
|
||||
constexpr size_t DATA_LEN_BYTE = 2;
|
||||
|
||||
constexpr int TIME_OUT_MAX = 3000;
|
||||
|
||||
// Timeot ms
|
||||
constexpr int TIME_OUT_INIT_CHMOD = 500;
|
||||
|
||||
typedef struct InternalCommand {
|
||||
uint16_t cbsh;
|
||||
uint16_t cbofp;
|
||||
uint16_t opcode;
|
||||
} InternalCommand;
|
||||
|
||||
InternalCommand g_internalCommand = {0, 0, 0};
|
||||
|
||||
constexpr size_t SLE_VENDOR_INVALID_DATA_LEN = 0;
|
||||
|
||||
VendorInterface::VendorInterface()
|
||||
{
|
||||
timer_ = std::make_unique<OHOS::Utils::Timer>("NearlinkOffFindTimer");
|
||||
timer_->Setup();
|
||||
offFindTimerId_ = 0;
|
||||
}
|
||||
|
||||
VendorInterface::~VendorInterface()
|
||||
{
|
||||
if (timer_) {
|
||||
timer_->Shutdown();
|
||||
}
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
bool VendorInterface::SetSwitchHostTimer()
|
||||
{
|
||||
if (timer_ == nullptr) {
|
||||
HDF_LOGE("timer_ is nulptr");
|
||||
return false;
|
||||
}
|
||||
auto func = []() {
|
||||
HDF_LOGI("SetSwitchHost TimeOut");
|
||||
VendorInterface::GetInstance()->OnInitCallback(OFF_FIND_FAIL);
|
||||
};
|
||||
uint32_t timeOut = TIME_OUT_MAX;
|
||||
if (LoadVendorCommonLibrary() == OFF_FIND_SUCCESS &&
|
||||
vendorCommInterface_->getRegisterTimerDuration != NULL) {
|
||||
timeOut = vendorCommInterface_->getRegisterTimerDuration(chipType_);
|
||||
}
|
||||
uint32_t ret = timer_->Register(func, timeOut, true); // only support once timer now
|
||||
if (ret == OHOS::Utils::TIMER_ERR_DEAL_FAILED) {
|
||||
HDF_LOGE("Register timer failed");
|
||||
return false;
|
||||
}
|
||||
offFindTimerId_ = ret;
|
||||
HDF_LOGI("offFindTimerId_ set: %{public}u", offFindTimerId_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VendorInterface::DliPacketHearderGet(uint16_t paramLen)
|
||||
{
|
||||
offFindDli_.push_back(DLI_PACKET_TYPE_SLE_CMD);
|
||||
offFindDli_.push_back(static_cast<uint8_t>(DLI_SET_POWER_OFF_PARAM));
|
||||
offFindDli_.push_back(static_cast<uint8_t>((DLI_SET_POWER_OFF_PARAM) >> OFFSET_EIGHT_BITS));
|
||||
|
||||
// Total data len in header
|
||||
offFindDli_.push_back(static_cast<uint8_t>(paramLen - DLI_PACKET_HEADER_SIZE));
|
||||
offFindDli_.push_back(static_cast<uint8_t>((paramLen - DLI_PACKET_HEADER_SIZE) >> OFFSET_EIGHT_BITS));
|
||||
|
||||
// Total data len in data head
|
||||
offFindDli_.push_back(static_cast<uint8_t>(paramLen - DLI_PACKET_HEADER_SIZE));
|
||||
offFindDli_.push_back(static_cast<uint8_t>((paramLen - DLI_PACKET_HEADER_SIZE) >> OFFSET_EIGHT_BITS));
|
||||
}
|
||||
|
||||
#ifdef SEND_DISABLE_OFF_FIND_DLI
|
||||
void VendorInterface::DisableDliPacketHearderGet()
|
||||
{
|
||||
// disable offfind cmd
|
||||
offFindDli_.push_back(DLI_PACKET_TYPE_SLE_CMD);
|
||||
offFindDli_.push_back(DLI_DISABLE_OFFFIDN_CMD);
|
||||
offFindDli_.push_back(DLI_DISABLE_OFFFIDN_PARAM);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t VendorInterface::GetSleCapability(int power)
|
||||
{
|
||||
uint8_t sleCapability = power <= BATTERY_ENTRY ? 0 : OF_SLE_ADV_ENABLE;
|
||||
if (OHOS::system::GetBoolParameter("const.nearlink.support.off_ring", false) && sleCapability != 0) {
|
||||
sleCapability = sleCapability | OF_SLE_RING_SUPPORT;
|
||||
}
|
||||
return sleCapability;
|
||||
}
|
||||
|
||||
bool VendorInterface::PowerOffDliGet(
|
||||
const std::vector<OffFindParam>& data, const OffFindExtraInfo& info, size_t paramsCnt)
|
||||
{
|
||||
HDF_LOGI("data[%{public}zu]udid[%{public}zu]uid[%{public}zu]", data.size(), info.udid.size(), info.uid.size());
|
||||
if (data.size() != paramsCnt || info.udid.size() > DEVICE_ID_LEN || info.uid.size() > USER_ID_LEN) {
|
||||
return false;
|
||||
}
|
||||
uint8_t sleCapability = GetSleCapability(info.battery);
|
||||
HDF_LOGI("power[%{public}d] sle[%{public}d]", info.battery, sleCapability);
|
||||
uint16_t paramLen = DLI_PACKET_HEADER_SIZE + ADV_FLAG_SIZE + DLI_DATA_LEN_SIZE + info.udid.size() + info.uid.size()
|
||||
+ data.size() * DLI_DATA_LEN_SIZE;
|
||||
uint16_t dataLen = 0;
|
||||
offFindDli_.reserve(static_cast<int>(paramLen));
|
||||
DliPacketHearderGet(paramLen);
|
||||
offFindDli_.push_back(1); // ble adv flag (default on)
|
||||
offFindDli_.push_back(sleCapability); // sle capability
|
||||
offFindDli_.push_back(info.udid.size());
|
||||
offFindDli_.insert(offFindDli_.end(), info.udid.begin(), info.udid.end());
|
||||
offFindDli_.push_back(info.uid.size());
|
||||
offFindDli_.insert(offFindDli_.end(), info.uid.begin(), info.uid.end());
|
||||
offFindDli_.insert(offFindDli_.end(), data.size());
|
||||
for (size_t i = 0; i < data.size(); i++) {
|
||||
HDF_LOGI("advertising key or cmac len [%{public}zu][%{public}zu][%{public}zu]",
|
||||
data[i].publicKey.size(), data[i].cmac.size(), data[i].aesKey.size());
|
||||
if (data[i].publicKey.size() > ADV_KEY_LEN || data[i].cmac.size() > ADV_CMAC_LEN ||
|
||||
data[i].aesKey.size() > ADV_KEY_LEN) {
|
||||
return false;
|
||||
}
|
||||
offFindDli_.push_back(data[i].publicKey.size());
|
||||
offFindDli_.insert(offFindDli_.end(), data[i].publicKey.begin(), data[i].publicKey.end());
|
||||
offFindDli_.push_back(data[i].cmac.size());
|
||||
offFindDli_.insert(offFindDli_.end(), data[i].cmac.begin(), data[i].cmac.end());
|
||||
offFindDli_.push_back(data[i].aesKey.size());
|
||||
offFindDli_.insert(offFindDli_.end(), data[i].aesKey.begin(), data[i].aesKey.end());
|
||||
std::vector<uint8_t> advTime(DLI_ADVTIME_SIZE);
|
||||
for (size_t j = 0; j < DLI_ADVTIME_SIZE; j++) {
|
||||
advTime[DLI_ADVTIME_SIZE - j - 1] =
|
||||
(data[i].advTime >> ((DLI_ADVTIME_SIZE-1 - j) * OFFSET_EIGHT_BITS)) & 0xFF;
|
||||
}
|
||||
offFindDli_.insert(offFindDli_.end(), advTime.begin(), advTime.end());
|
||||
dataLen += data[i].publicKey.size() + data[i].cmac.size() + data[i].aesKey.size() + DLI_ADVTIME_SIZE;
|
||||
}
|
||||
offFindDli_[THIRD_BYTE] = static_cast<uint8_t>(paramLen + dataLen + DATA_LEN_BYTE - DLI_PACKET_HEADER_SIZE);
|
||||
offFindDli_[FOURTH_BYTE] = static_cast<uint8_t>(
|
||||
(paramLen + dataLen + DATA_LEN_BYTE - DLI_PACKET_HEADER_SIZE) >> OFFSET_EIGHT_BITS);
|
||||
offFindDli_[FIFTH_BYTE] = static_cast<uint8_t>(paramLen + dataLen - DLI_PACKET_HEADER_SIZE);
|
||||
offFindDli_[SIXTH_BYTE] = static_cast<uint8_t>(
|
||||
(paramLen + dataLen - DLI_PACKET_HEADER_SIZE) >> OFFSET_EIGHT_BITS);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VendorInterface::SwitchHostDliGet(std::vector<uint8_t>& data)
|
||||
{
|
||||
data.push_back(DLI_PACKET_TYPE_SLE_CMD);
|
||||
data.push_back(static_cast<uint8_t>(DLI_SWITCH_HOST));
|
||||
data.push_back(static_cast<uint8_t>((DLI_SWITCH_HOST) >> OFFSET_EIGHT_BITS));
|
||||
data.push_back(0x00);
|
||||
data.push_back(0x00);
|
||||
g_internalCommand.cbsh = 1;
|
||||
g_internalCommand.opcode = DLI_SWITCH_HOST;
|
||||
}
|
||||
|
||||
bool VendorInterface::WatchDliChannel()
|
||||
{
|
||||
int channel[DLI_MAX_CHANNEL] = {0};
|
||||
int channelCount = vendorInterface_->op(OffFindOpcodeT::SLE_OP_DLI_CHANNEL_OPEN, static_cast<void *>(channel));
|
||||
if (channelCount < 1 || channelCount > DLI_MAX_CHANNEL) {
|
||||
HDF_LOGE("vendorInterface_->op SLE_OP_DLI_CHANNEL_OPEN failed ret:%{public}d.", channelCount);
|
||||
return false;
|
||||
}
|
||||
if (channelCount == 1) {
|
||||
auto h4 = std::make_shared<OffFind::H4Protocol>(channel[0],
|
||||
std::bind(&VendorInterface::OnEventReceived, this, std::placeholders::_1));
|
||||
watcher_.AddFdToWatcher(channel[0], std::bind(&OffFind::H4Protocol::ReadData, h4, std::placeholders::_1));
|
||||
dli_ = h4;
|
||||
} else {
|
||||
HDF_LOGE("invalid channel count:%d.", channelCount);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VendorInterface::SetReservedPower()
|
||||
{
|
||||
if (isInitialized_.load()) {
|
||||
HDF_LOGE("already Initialized");
|
||||
return;
|
||||
}
|
||||
std::lock_guard<ffrt::recursive_mutex> lock(processMutex_);
|
||||
if (vendorHandle_ == nullptr || vendorInterface_ == nullptr) {
|
||||
vendorHandle_ = dlopen(GetFullVendorName(), RTLD_NOW);
|
||||
if (vendorHandle_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface dlopen %{public}s failed, error code: %{public}s", offFindVendorName_.c_str(),
|
||||
dlerror());
|
||||
return;
|
||||
}
|
||||
vendorInterface_ =
|
||||
reinterpret_cast<OffFindVendorInterfaceT *>(dlsym(vendorHandle_, OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME));
|
||||
if (vendorInterface_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface dlsym %{public}s failed.", OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// dev_offfind node init time sometimes later than findnetwork process init when startup
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(TIME_OUT_INIT_CHMOD));
|
||||
vendorInterface_->init();
|
||||
int powerSetFlag = SET_RESERVED_POWER;
|
||||
vendorInterface_->op(OffFindOpcodeT::SLE_OP_RESERVERD_POWER_SET, static_cast<void *>(&powerSetFlag));
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
int VendorInterface::GetPowerTimeParameter(const OffFindExtraInfo& info, size_t paramsCnt)
|
||||
{
|
||||
int power = info.battery <= BATTERY_ENTRY ?
|
||||
OHOS::system::GetIntParameter<int>("const.nearlink.off_find.low_battery_time", DOWN_POWER_TIME)
|
||||
: OHOS::system::GetIntParameter<int>("const.nearlink.off_find.high_battery_time", UP_POWER_TIME);
|
||||
|
||||
if (paramsCnt == SEVEN_DAYS_ADV_DATA_LEN && info.battery > BATTERY_HIGH_ENTRY) {
|
||||
power = HIGH_POWER_TIME;
|
||||
}
|
||||
|
||||
bool isAirOta = std::all_of(info.uid.begin(), info.uid.end(), [](unsigned char c) {
|
||||
return c == 0xFF;
|
||||
});
|
||||
if (!info.uid.empty() && isAirOta) {
|
||||
power = AIR_OTA_POWER_TIME;
|
||||
}
|
||||
|
||||
int chipStep = OHOS::system::GetIntParameter<int>("const.nearlink.off_find.chip_step", DEFAULT_CHIP_STEP);
|
||||
if (chipStep <= 0) {
|
||||
chipStep = DEFAULT_CHIP_STEP;
|
||||
}
|
||||
if (chipStep > 0) {
|
||||
power /= chipStep;
|
||||
}
|
||||
return power;
|
||||
}
|
||||
|
||||
OffFindErrorCode VendorInterface::OpenAndSymDl()
|
||||
{
|
||||
if (vendorHandle_ == nullptr || vendorInterface_ == nullptr) {
|
||||
vendorHandle_ = dlopen(GetFullVendorName(), RTLD_NOW);
|
||||
if (vendorHandle_ == nullptr) {
|
||||
HDF_LOGE("dlopen %{public}s failed, error code: %{public}s", offFindVendorName_.c_str(), dlerror());
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
vendorInterface_ =
|
||||
reinterpret_cast<OffFindVendorInterfaceT *>(dlsym(vendorHandle_, OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME));
|
||||
if (vendorInterface_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface dlsym %{public}s failed.", OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME);
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
}
|
||||
return OFF_FIND_SUCCESS;
|
||||
}
|
||||
|
||||
OffFindErrorCode VendorInterface::LoadVendorCommonLibrary()
|
||||
{
|
||||
if (vendorCommHandle_ != nullptr && vendorCommInterface_ != nullptr) {
|
||||
return OFF_FIND_SUCCESS;
|
||||
}
|
||||
vendorCommHandle_ = dlopen(OFF_FIND_VENDOR_COMMON_NAME, RTLD_NOW);
|
||||
if (vendorCommHandle_ == nullptr) {
|
||||
HDF_LOGE("dlopen %{public}s failed, errCode: %{public}s", OFF_FIND_VENDOR_COMMON_NAME, dlerror());
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
vendorCommInterface_ = reinterpret_cast<OffFindVendorCommInterfaceT *>(dlsym(vendorCommHandle_,
|
||||
OFF_FIND_VENDOR_COMMON_INTERFACE_SYMBOL_NAME));
|
||||
if (vendorCommInterface_ == nullptr) {
|
||||
HDF_LOGE("dlsym failed %{public}s, err: %{public}s", OFF_FIND_VENDOR_COMMON_INTERFACE_SYMBOL_NAME, dlerror());
|
||||
dlclose(vendorCommHandle_);
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
HDF_LOGI("LoadVendorCommonLibrary success %{public}s", OFF_FIND_VENDOR_COMMON_NAME);
|
||||
return OFF_FIND_SUCCESS;
|
||||
}
|
||||
|
||||
OffFindErrorCode VendorInterface::EnableOffFindMode(InitializeCompleteCallback initializeCompleteCallback,
|
||||
const std::vector<OffFindParam>& data, const OffFindExtraInfo& info)
|
||||
{
|
||||
std::lock_guard<ffrt::recursive_mutex> lock(processMutex_);
|
||||
size_t paramsCnt =
|
||||
OHOS::system::GetUintParameter<size_t>("const.findnetwork.shutdown_params.count", DEFAULT_ADV_DATA_LEN);
|
||||
HDF_LOGI("EnableOffFindMode Begin, %{public}zu params", paramsCnt);
|
||||
if (!PowerOffDliGet(data, info, paramsCnt)) {
|
||||
HDF_LOGE("PowerOffDliGet ERROR");
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
initializeCompleteCallback_ = initializeCompleteCallback;
|
||||
if (OpenAndSymDl() != OFF_FIND_SUCCESS || LoadVendorCommonLibrary() != OFF_FIND_SUCCESS) {
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
vendorInterface_->init();
|
||||
if (!WatchDliChannel()) {
|
||||
HDF_LOGE("WatchDliChannel Init Fail");
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
if (vendorCommInterface_->isNeedWatcherStart != NULL &&
|
||||
vendorCommInterface_->isNeedWatcherStart(chipType_) && !watcher_.Start()) {
|
||||
HDF_LOGE("watcher start failed.");
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
int powerTime = GetPowerTimeParameter(info, paramsCnt);
|
||||
HDF_LOGI("battery[%{public}d] and powerTime[%{public}d]", info.battery, powerTime);
|
||||
|
||||
if (vendorCommInterface_->modifyPowerProtect != NULL &&
|
||||
vendorCommInterface_->modifyPowerProtect(powerTime, info.battery) != OFF_FIND_SUCCESS) {
|
||||
HDF_LOGE("modifyPowerProtect failed");
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
|
||||
if (!SetSwitchHostTimer()) {
|
||||
HDF_LOGE("OffFind Mode SetTimer failed");
|
||||
return OFF_FIND_SYNC_FAIL;
|
||||
}
|
||||
int ret = vendorInterface_->op(OffFindOpcodeT::SLE_OP_OFF_FIND_MODE_ENABLE, static_cast<void *>(&powerTime));
|
||||
if (ret < 0) {
|
||||
HDF_LOGE("OffFind Mode Enable failed");
|
||||
return OFF_FIND_FAIL;
|
||||
}
|
||||
g_internalCommand.cbofp = 1;
|
||||
dliCompleteFlag_ = false;
|
||||
dli_->SendPacket(offFindDli_);
|
||||
offFindDli_.clear();
|
||||
return OFF_FIND_SUCCESS;
|
||||
}
|
||||
|
||||
void VendorInterface::RegisterClearOffFindCallback(ClearIpcCallback clearIpcCallback)
|
||||
{
|
||||
clearIpcCallback_ = clearIpcCallback;
|
||||
}
|
||||
|
||||
bool VendorInterface::Initialize(InitializeCompleteCallback initializeCompleteCallback,
|
||||
const std::vector<OffFindParam>& data, const OffFindExtraInfo& info)
|
||||
{
|
||||
if (isInitialized_.load()) {
|
||||
HDF_LOGE("already Initialized");
|
||||
return false;
|
||||
}
|
||||
isInitialized_.store(true);
|
||||
OffFindErrorCode ret = OFF_FIND_SUCCESS;
|
||||
ret = EnableOffFindMode(initializeCompleteCallback, data, info);
|
||||
if (ret == OFF_FIND_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
OnInitCallback(ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* VendorInterface::GetFullVendorName()
|
||||
{
|
||||
if (offFindVendorName_ != "") {
|
||||
return offFindVendorName_.c_str();
|
||||
}
|
||||
offFindVendorName_ = OFF_FIND_VENDOR_NAME;
|
||||
std::string sleChipType = OHOS::system::GetParameter(SLE_OFF_FIND_CHIP_TYPE, "");
|
||||
HDF_LOGI("sleChipType is %{public}s", sleChipType.c_str());
|
||||
if (!sleChipType.empty()) {
|
||||
offFindVendorName_.append("_");
|
||||
offFindVendorName_.append(sleChipType.c_str());
|
||||
chipType_.append(sleChipType);
|
||||
}
|
||||
offFindVendorName_.append(".z.so");
|
||||
HDF_LOGI("vendor name is %{public}s", offFindVendorName_.c_str());
|
||||
return offFindVendorName_.c_str();
|
||||
}
|
||||
|
||||
void VendorInterface::DisableOffFindMode()
|
||||
{
|
||||
std::lock_guard<ffrt::recursive_mutex> lock(processMutex_);
|
||||
if (vendorHandle_ == nullptr || vendorInterface_ == nullptr) {
|
||||
vendorHandle_ = dlopen(GetFullVendorName(), RTLD_NOW);
|
||||
if (vendorHandle_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface dlopen %{public}s failed, error code: %{public}s", offFindVendorName_.c_str(),
|
||||
dlerror());
|
||||
return;
|
||||
}
|
||||
vendorInterface_ =
|
||||
reinterpret_cast<OffFindVendorInterfaceT *>(dlsym(vendorHandle_, OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME));
|
||||
if (vendorInterface_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface dlsym %{public}s failed.", OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME);
|
||||
return;
|
||||
}
|
||||
}
|
||||
vendorInterface_->init();
|
||||
#ifdef SEND_DISABLE_OFF_FIND_DLI
|
||||
if (!WatchDliChannel()) {
|
||||
HDF_LOGE("WatchDliChannel Init Fail");
|
||||
}
|
||||
DisableDliPacketHearderGet();
|
||||
if (dli_ != nullptr) {
|
||||
dli_->SendPacket(offFindDli_);
|
||||
}
|
||||
offFindDli_.clear();
|
||||
vendorInterface_->op(OffFindOpcodeT::SLE_OP_DLI_CHANNEL_CLOSE, nullptr);
|
||||
#endif
|
||||
int powerSetFlag = CLEAR_RESERVED_POWER;
|
||||
vendorInterface_->op(OffFindOpcodeT::SLE_OP_RESERVERD_POWER_SET, static_cast<void *>(&powerSetFlag));
|
||||
isInitialized_.store(false);
|
||||
vendorInterface_->op(OffFindOpcodeT::SLE_OP_OFF_FIND_MODE_DISABLE, nullptr);
|
||||
vendorInterface_->close();
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
void VendorInterface::CleanUp()
|
||||
{
|
||||
std::lock_guard<ffrt::recursive_mutex> lock(processMutex_);
|
||||
if (vendorInterface_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface::CleanUp, vendorInterface_ is nullptr.");
|
||||
return;
|
||||
}
|
||||
HDF_LOGI("off find clean up");
|
||||
watcher_.Stop();
|
||||
dli_ = nullptr;
|
||||
vendorInterface_ = nullptr;
|
||||
initializeCompleteCallback_ = nullptr;
|
||||
eventDataCallback_ = nullptr;
|
||||
dlclose(vendorHandle_);
|
||||
vendorCommInterface_ = nullptr;
|
||||
dlclose(vendorCommHandle_);
|
||||
}
|
||||
|
||||
size_t VendorInterface::SendPacket(const std::vector<uint8_t> &packet)
|
||||
{
|
||||
if (vendorInterface_ == nullptr || dli_ == nullptr) {
|
||||
HDF_LOGE("VendorInterface::SendPacket, vendorInterface_ is nullptr.");
|
||||
return SLE_VENDOR_INVALID_DATA_LEN;
|
||||
}
|
||||
|
||||
watcher_.SetTimeout(std::chrono::milliseconds(lpmTimer_), std::bind(&VendorInterface::WatcherTimeout, this));
|
||||
|
||||
return dli_->SendPacket(packet);
|
||||
}
|
||||
|
||||
void VendorInterface::OnInitCallback(OffFindErrorCode result)
|
||||
{
|
||||
HDF_LOGI("OnInitCallback %{public}d", result);
|
||||
OffFindSwitchResult status = OffFindSwitchResult::INITIALIZATION_ERROR;
|
||||
if (result != OFF_FIND_SYNC_FAIL) {
|
||||
if (offFindTimerId_ == 0) {
|
||||
HDF_LOGE("offFindTimerId_ is 0, no registered timer");
|
||||
} else {
|
||||
HDF_LOGI("OnInitCallback offFindTimerId_: %{public}d", offFindTimerId_);
|
||||
if (timer_ == nullptr) {
|
||||
HDF_LOGE("timer_ is nulptr");
|
||||
} else {
|
||||
timer_->Unregister(offFindTimerId_);
|
||||
}
|
||||
}
|
||||
if (result == OFF_FIND_SUCCESS) {
|
||||
status = OffFindSwitchResult::SUCCESS;
|
||||
} else {
|
||||
vendorInterface_->op(OffFindOpcodeT::SLE_OP_OFF_FIND_MODE_DISABLE, nullptr);
|
||||
}
|
||||
}
|
||||
isInitialized_.store(false);
|
||||
if (initializeCompleteCallback_) {
|
||||
initializeCompleteCallback_(status);
|
||||
initializeCompleteCallback_ = nullptr;
|
||||
if (clearIpcCallback_) {
|
||||
clearIpcCallback_();
|
||||
}
|
||||
}
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
bool VendorInterface::EventReceivedHandler(const std::vector<uint8_t> &data)
|
||||
{
|
||||
if (data.size() < DLI_PACKET_MIN_SIZE) {
|
||||
HDF_LOGE("packet len err , [%{public}zu]", data.size());
|
||||
return false;
|
||||
}
|
||||
uint16_t eventOpcode = data[0] | (data[1] << OFFSET_EIGHT_BITS);
|
||||
// 如果 eventOpcode 不是 SLE_DLI_COMMAND_COMPLETE_EVENT,可能是残留数据不做任何处理,直接返回 true,后续正常的COMPLETE_EVENT会继续返回
|
||||
if (eventOpcode != SLE_DLI_COMMAND_COMPLETE_EVENT) {
|
||||
HDF_LOGW("eventOpcode[%{public}04X] is not complete event", eventOpcode);
|
||||
return true;
|
||||
}
|
||||
size_t opcodeOffset = dli_->GetPacketHeaderInfo(DLI_PACKET_TYPE_SLE_EVENT).headerSize;
|
||||
uint16_t opcode = data[opcodeOffset] + (data[opcodeOffset + 1] << OFFSET_EIGHT_BITS);
|
||||
HDF_LOGI("opcode[%{public}04X], cbofp[%{public}d], cbsh[%{public}d], status[%{public}d]",
|
||||
opcode, g_internalCommand.cbofp, g_internalCommand.cbsh, data[opcodeOffset + OFFSET_STATUS]);
|
||||
if (g_internalCommand.cbofp != 0 && opcode == DLI_SET_POWER_OFF_PARAM) {
|
||||
if (data[opcodeOffset + OFFSET_STATUS] != 0) {
|
||||
HDF_LOGE("set param event status[%{public}d] error", data[opcodeOffset + OFFSET_STATUS]);
|
||||
return false;
|
||||
}
|
||||
g_internalCommand.cbofp = 0;
|
||||
g_internalCommand.cbsh = 1;
|
||||
g_internalCommand.opcode = DLI_SWITCH_HOST;
|
||||
std::vector<uint8_t> switchHostDli;
|
||||
switchHostDli.reserve(DLI_PACKET_HEADER_SIZE);
|
||||
SwitchHostDliGet(switchHostDli);
|
||||
dli_->SendPacket(switchHostDli);
|
||||
return true;
|
||||
} else if (g_internalCommand.cbsh != 0 && opcode == DLI_SWITCH_HOST) {
|
||||
if (data[opcodeOffset + OFFSET_STATUS] != 0) {
|
||||
HDF_LOGE("switch host status[%{public}d] error", data[opcodeOffset + OFFSET_STATUS]);
|
||||
return false;
|
||||
}
|
||||
int ret = vendorInterface_->op(OffFindOpcodeT::SLE_OP_OFF_FIND_POWER_PROTECT_ENABLE, nullptr);
|
||||
if (ret < 0) {
|
||||
HDF_LOGE("OffFind power cfg config failed");
|
||||
return false;
|
||||
}
|
||||
dliCompleteFlag_ = true;
|
||||
g_internalCommand.cbsh = 0;
|
||||
return true;
|
||||
} else {
|
||||
HDF_LOGE("unknown dli");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void VendorInterface::OnEventReceived(const std::vector<uint8_t> &data)
|
||||
{
|
||||
Nearlink::DoInDliThread([this, acbData = data]() {
|
||||
this->OnEventReceivedTask(acbData);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
void VendorInterface::OnEventReceivedTask(const std::vector<uint8_t> &data)
|
||||
{
|
||||
HDF_LOGI("OnEventReceivedTask");
|
||||
bool ret = EventReceivedHandler(data);
|
||||
if (ret && dliCompleteFlag_) {
|
||||
OnInitCallback(OFF_FIND_SUCCESS);
|
||||
} else if (!ret) {
|
||||
OnInitCallback(OFF_FIND_FAIL);
|
||||
} else {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
void VendorInterface::WatcherTimeout()
|
||||
{
|
||||
HDF_LOGI("fd wait out of time, no data ready");
|
||||
}
|
||||
} // namespace V1_0
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_HDI_NEARLINK_OFF_FIND_V1_0_VENDOR_INTERFACE_H
|
||||
#define OHOS_HDI_NEARLINK_OFF_FIND_V1_0_VENDOR_INTERFACE_H
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "timer.h"
|
||||
#include "singleton.h"
|
||||
#include "off_find_hdi_constant.h"
|
||||
#include "dli_internal.h"
|
||||
#include "dli_protocol.h"
|
||||
#include "dli_watcher.h"
|
||||
#include "ffrt_inner.h"
|
||||
#include "v1_0/off_find_types.h"
|
||||
#include "ohos_off_find_vendor_lib.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
namespace V1_0 {
|
||||
class VendorInterface : public DelayedSingleton<VendorInterface> {
|
||||
public:
|
||||
using InitializeCompleteCallback = std::function<void(int32_t result)>;
|
||||
using ClearIpcCallback = std::function<void()>;
|
||||
using ReceiveDataCallback = DliProtocol::DliDataCallback;
|
||||
void SetReservedPower();
|
||||
void RegisterClearOffFindCallback(ClearIpcCallback clearIpcCallback
|
||||
);
|
||||
bool Initialize(InitializeCompleteCallback initializeCompleteCallback, const std::vector<OffFindParam>& data,
|
||||
const OffFindExtraInfo& info);
|
||||
void DisableOffFindMode();
|
||||
void CleanUp();
|
||||
size_t SendPacket(const std::vector<uint8_t> &packet);
|
||||
void SetSleAddress(uint8_t *localSleAddr);
|
||||
uint8_t *SetAddress(uint8_t *addr);
|
||||
private:
|
||||
OffFindErrorCode EnableOffFindMode(InitializeCompleteCallback initializeCompleteCallback,
|
||||
const std::vector<OffFindParam>& data, const OffFindExtraInfo& info);
|
||||
OffFindErrorCode OpenAndSymDl();
|
||||
OffFindErrorCode LoadVendorCommonLibrary();
|
||||
bool EventReceivedHandler(const std::vector<uint8_t> &data);
|
||||
void OnInitCallback(OffFindErrorCode result);
|
||||
void OnEventReceived(const std::vector<uint8_t> &data);
|
||||
void OnEventReceivedTask(const std::vector<uint8_t> &data);
|
||||
bool WatchDliChannel();
|
||||
void WatcherTimeout();
|
||||
InitializeCompleteCallback initializeCompleteCallback_;
|
||||
ClearIpcCallback clearIpcCallback_;
|
||||
ReceiveDataCallback eventDataCallback_;
|
||||
void* vendorHandle_ = nullptr;
|
||||
OffFindVendorInterfaceT *vendorInterface_ = nullptr;
|
||||
void* vendorCommHandle_ = nullptr;
|
||||
OffFindVendorCommInterfaceT *vendorCommInterface_ = nullptr;
|
||||
DliWatcher watcher_;
|
||||
std::shared_ptr<DliProtocol> dli_ = nullptr;
|
||||
std::vector<uint8_t> offFindDli_;
|
||||
uint16_t vendorSentOpcode_ = 0;
|
||||
uint32_t lpmTimer_ = 0;
|
||||
std::unique_ptr<OHOS::Utils::Timer> timer_ {nullptr};
|
||||
uint32_t offFindTimerId_;
|
||||
std::string offFindVendorName_ = "";
|
||||
std::string chipType_ = "";
|
||||
bool dliCompleteFlag_ = false;
|
||||
void DliPacketHearderGet(uint16_t paramLen);
|
||||
#ifdef SEND_DISABLE_OFF_FIND_DLI
|
||||
void DisableDliPacketHearderGet();
|
||||
#endif
|
||||
bool SetSwitchHostTimer();
|
||||
uint8_t GetSleCapability(int power);
|
||||
bool PowerOffDliGet(const std::vector<OffFindParam>& data, const OffFindExtraInfo& info, size_t paramsCnt);
|
||||
void SwitchHostDliGet(std::vector<uint8_t>& data);
|
||||
int GetPowerTimeParameter(const OffFindExtraInfo& info, size_t paramsCnt);
|
||||
DECLARE_DELAYED_SINGLETON(VendorInterface);
|
||||
DISALLOW_COPY_AND_MOVE(VendorInterface);
|
||||
ffrt::recursive_mutex processMutex_;
|
||||
const char* GetFullVendorName();
|
||||
std::atomic_bool isInitialized_ = false;
|
||||
};
|
||||
} // namespace V1_0
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // namespace OHOS
|
||||
#endif /* OHOS_HDI_NEARLINK_OFF_FIND_V1_0_VENDOR_INTERFACE_H */
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <hdf_base.h>
|
||||
#include <hdf_device_desc.h>
|
||||
#include <hdf_log.h>
|
||||
#include <hdf_sbuf_ipc.h>
|
||||
#include "v1_0/off_find_interface_stub.h"
|
||||
|
||||
#define HDF_LOG_TAG off_find_interface_driver
|
||||
|
||||
using namespace OHOS::HDI::Nearlink::OffFind::V1_0;
|
||||
|
||||
struct HdfOffFindInterfaceHost {
|
||||
struct IDeviceIoService ioService;
|
||||
OHOS::sptr<OHOS::IRemoteObject> stub;
|
||||
HdfOffFindInterfaceHost()
|
||||
{
|
||||
ioService.object.objectId = 0;
|
||||
ioService.Open = nullptr;
|
||||
ioService.Release = nullptr;
|
||||
ioService.Dispatch = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static int32_t OffFindInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
|
||||
struct HdfSBuf *reply)
|
||||
{
|
||||
auto *hdfOffFindInterfaceHost = CONTAINER_OF(client->device->service, struct HdfOffFindInterfaceHost, ioService);
|
||||
|
||||
OHOS::MessageParcel *dataParcel = nullptr;
|
||||
OHOS::MessageParcel *replyParcel = nullptr;
|
||||
OHOS::MessageOption option;
|
||||
|
||||
if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
|
||||
HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__);
|
||||
return HDF_ERR_INVALID_PARAM;
|
||||
}
|
||||
if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
|
||||
HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__);
|
||||
return HDF_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return hdfOffFindInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
|
||||
}
|
||||
|
||||
static int HdfOffFindInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
|
||||
{
|
||||
HDF_LOGI("%{public}s: driver init start", __func__);
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
static int HdfOffFindInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
|
||||
{
|
||||
HDF_LOGI("%{public}s: driver bind start", __func__);
|
||||
auto *hdfOffFindInterfaceHost = new (std::nothrow) HdfOffFindInterfaceHost;
|
||||
if (hdfOffFindInterfaceHost == nullptr) {
|
||||
HDF_LOGE("%{public}s: failed to create create HdfOffFindInterfaceHost object", __func__);
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
|
||||
hdfOffFindInterfaceHost->ioService.Dispatch = OffFindInterfaceDriverDispatch;
|
||||
hdfOffFindInterfaceHost->ioService.Open = NULL;
|
||||
hdfOffFindInterfaceHost->ioService.Release = NULL;
|
||||
|
||||
auto serviceImpl = OHOS::HDI::Nearlink::OffFind::V1_0::IOffFindInterface::Get(true);
|
||||
if (serviceImpl == nullptr) {
|
||||
HDF_LOGE("%{public}s: failed to get of implement service", __func__);
|
||||
delete hdfOffFindInterfaceHost;
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
|
||||
hdfOffFindInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
|
||||
OHOS::HDI::Nearlink::OffFind::V1_0::IOffFindInterface::GetDescriptor());
|
||||
if (hdfOffFindInterfaceHost->stub == nullptr) {
|
||||
HDF_LOGE("%{public}s: failed to get stub object", __func__);
|
||||
delete hdfOffFindInterfaceHost;
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
|
||||
deviceObject->service = &hdfOffFindInterfaceHost->ioService;
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
static void HdfOffFindInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
|
||||
{
|
||||
HDF_LOGI("%{public}s: driver release start", __func__);
|
||||
if (deviceObject->service == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *hdfOffFindInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfOffFindInterfaceHost, ioService);
|
||||
if (hdfOffFindInterfaceHost != nullptr) {
|
||||
delete hdfOffFindInterfaceHost;
|
||||
}
|
||||
}
|
||||
|
||||
struct HdfDriverEntry g_offfindinterfaceDriverEntry = {
|
||||
.moduleVersion = 1,
|
||||
.moduleName = "off_find",
|
||||
.Bind = HdfOffFindInterfaceDriverBind,
|
||||
.Init = HdfOffFindInterfaceDriverInit,
|
||||
.Release = HdfOffFindInterfaceDriverRelease,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
HDF_INIT(g_offfindinterfaceDriverEntry);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <hdf_base.h>
|
||||
#include <iproxy_broker.h>
|
||||
#include "off_find_log.h"
|
||||
#include "vendor_interface.h"
|
||||
#include "off_find_interface_impl.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
namespace V1_0 {
|
||||
using VendorInterface = OHOS::HDI::Nearlink::OffFind::V1_0::VendorInterface;
|
||||
const std::string OFF_FIND_FFRT_THREAD = "OffFindHdf";
|
||||
|
||||
extern "C" IOffFindInterface *OffFindInterfaceImplGetInstance(void)
|
||||
{
|
||||
return new (std::nothrow) OffFindInterfaceImpl();
|
||||
}
|
||||
|
||||
|
||||
OffFindInterfaceImpl::OffFindInterfaceImpl()
|
||||
{
|
||||
remoteDeathRecipient_ =
|
||||
new RemoteDeathRecipient(std::bind(&OffFindInterfaceImpl::OnRemoteDied, this, std::placeholders::_1));
|
||||
if (eventQueue_ != nullptr) {
|
||||
HDF_LOGI("eventQueue already init");
|
||||
} else {
|
||||
eventQueue_ = std::make_shared<ffrt::queue>(OFF_FIND_FFRT_THREAD.c_str());
|
||||
HDF_LOGI("Create a new eventQueue, threadName:%{public}s", OFF_FIND_FFRT_THREAD.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
OffFindInterfaceImpl::~OffFindInterfaceImpl()
|
||||
{
|
||||
if (callbacks_ != nullptr) {
|
||||
RemoveHciDeathRecipient(callbacks_);
|
||||
callbacks_ = nullptr;
|
||||
}
|
||||
if (eventQueue_) {
|
||||
eventQueue_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t OffFindInterfaceImpl::SetReservedPower()
|
||||
{
|
||||
HDF_LOGI("OffFindInterfaceImpl::SetReservedPower");
|
||||
auto func = []() {
|
||||
HDF_LOGI("asyc SetReservedPower work start");
|
||||
VendorInterface::GetInstance()->SetReservedPower();
|
||||
};
|
||||
|
||||
if (eventQueue_ == nullptr) {
|
||||
HDF_LOGE("eventQueue is nullptr!");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
eventQueue_->submit(func);
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t OffFindInterfaceImpl::EnableOffFind(
|
||||
const sptr<OHOS::HDI::Nearlink::OffFind::V1_0::IOffFindCallback>& callbackObj,
|
||||
const std::vector<OHOS::HDI::Nearlink::OffFind::V1_0::OffFindParam>& data,
|
||||
const OHOS::HDI::Nearlink::OffFind::V1_0::OffFindExtraInfo& info)
|
||||
{
|
||||
HDF_LOGI("OffFindInterfaceImpl::EnableOffFind");
|
||||
auto func = [callbackObj, data, info, this]() {
|
||||
HDF_LOGI("Enter EnableOffFind");
|
||||
if (callbackObj == nullptr) {
|
||||
HDF_LOGE("OffFindInterfaceImpl callbackObj null");
|
||||
return ;
|
||||
}
|
||||
VendorInterface::GetInstance()->RegisterClearOffFindCallback(
|
||||
[this]() {
|
||||
HDF_LOGI("clear callbacks is success !");
|
||||
if (callbacks_ != nullptr) {
|
||||
RemoveHciDeathRecipient(callbacks_);
|
||||
callbacks_ = nullptr;
|
||||
}
|
||||
}
|
||||
);
|
||||
bool result = VendorInterface::GetInstance()->Initialize(
|
||||
[callbackObj](int32_t result) {callbackObj->OnOffFindEnableResult(result); }, data, info);
|
||||
if (result) {
|
||||
callbacks_ = callbackObj;
|
||||
AddHciDeathRecipient(callbacks_);
|
||||
}
|
||||
};
|
||||
if (eventQueue_ == nullptr) {
|
||||
HDF_LOGE("eventQueue is nullptr!");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
eventQueue_->submit(func);
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t OffFindInterfaceImpl::DisableOffFind()
|
||||
{
|
||||
HDF_LOGI("OffFindInterfaceImpl::DisableOffFind");
|
||||
auto func = []() {
|
||||
HDF_LOGI("asyc disable work start");
|
||||
VendorInterface::GetInstance()->DisableOffFindMode();
|
||||
};
|
||||
|
||||
if (eventQueue_ == nullptr) {
|
||||
HDF_LOGE("eventQueue is nullptr!");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
eventQueue_->submit(func);
|
||||
VendorInterface::DestroyInstance();
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
void OffFindInterfaceImpl::OnRemoteDied(const wptr<IRemoteObject> &object)
|
||||
{
|
||||
HDF_LOGI("OffFindInterfaceImpl");
|
||||
callbacks_ = nullptr;
|
||||
VendorInterface::GetInstance()->CleanUp();
|
||||
VendorInterface::DestroyInstance();
|
||||
}
|
||||
|
||||
int32_t OffFindInterfaceImpl::AddHciDeathRecipient(const sptr<IOffFindCallback>& callbackObj)
|
||||
{
|
||||
HDF_LOGI("OffFindInterfaceImpl");
|
||||
const sptr<IRemoteObject>& remote = OHOS::HDI::hdi_objcast<IOffFindCallback>(callbackObj);
|
||||
if (!remote) {
|
||||
HDF_LOGE("remote is nullptr");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
bool result = remote->AddDeathRecipient(remoteDeathRecipient_);
|
||||
if (!result) {
|
||||
HDF_LOGE("OffFindInterfaceImpl AddDeathRecipient fail");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t OffFindInterfaceImpl::RemoveHciDeathRecipient(const sptr<IOffFindCallback>& callbackObj)
|
||||
{
|
||||
HDF_LOGI("OffFindInterfaceImpl");
|
||||
const sptr<IRemoteObject>& remote = OHOS::HDI::hdi_objcast<IOffFindCallback>(callbackObj);
|
||||
if (!remote) {
|
||||
HDF_LOGE("remote is nullptr");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
bool result = remote->RemoveDeathRecipient(remoteDeathRecipient_);
|
||||
if (!result) {
|
||||
HDF_LOGE("OffFindInterfaceImpl RemoveDeathRecipient fail");
|
||||
return HDF_FAILURE;
|
||||
}
|
||||
return HDF_SUCCESS;
|
||||
}
|
||||
|
||||
} // V1_0
|
||||
} // OffFind
|
||||
} // Nearlink
|
||||
} // HDI
|
||||
} // OHOS
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef OHOS_HDI_NEARLINK_OFF_FIND_V1_0_OFF_FINDINTERFACEIMPL_H
|
||||
#define OHOS_HDI_NEARLINK_OFF_FIND_V1_0_OFF_FINDINTERFACEIMPL_H
|
||||
|
||||
#include "v1_0/ioff_find_interface.h"
|
||||
#include "v1_0/ioff_find_callback.h"
|
||||
#include "remote_death_recipient.h"
|
||||
#include "ffrt_inner.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
namespace V1_0 {
|
||||
class OffFindInterfaceImpl : public OHOS::HDI::Nearlink::OffFind::V1_0::IOffFindInterface {
|
||||
public:
|
||||
OffFindInterfaceImpl();
|
||||
virtual ~OffFindInterfaceImpl();
|
||||
|
||||
int32_t SetReservedPower() override;
|
||||
int32_t EnableOffFind(const sptr<OHOS::HDI::Nearlink::OffFind::V1_0::IOffFindCallback>& callbackObj,
|
||||
const std::vector<OHOS::HDI::Nearlink::OffFind::V1_0::OffFindParam>& data,
|
||||
const OHOS::HDI::Nearlink::OffFind::V1_0::OffFindExtraInfo& info) override;
|
||||
|
||||
int32_t DisableOffFind() override;
|
||||
|
||||
private:
|
||||
void OnRemoteDied(const wptr<IRemoteObject> &object);
|
||||
sptr<IOffFindCallback> callbacks_ = nullptr;
|
||||
sptr<RemoteDeathRecipient> remoteDeathRecipient_ = nullptr;
|
||||
int32_t AddHciDeathRecipient(const sptr<IOffFindCallback>& callbackObj);
|
||||
int32_t RemoveHciDeathRecipient(const sptr<IOffFindCallback>& callbackObj);
|
||||
std::shared_ptr<ffrt::queue> eventQueue_ = nullptr;
|
||||
};
|
||||
} // V1_0
|
||||
} // OffFind
|
||||
} // Nearlink
|
||||
} // HDI
|
||||
} // OHOS
|
||||
|
||||
#endif // OHOS_HDI_NEARLINK_OFF_FIND_V1_0_OffFindInterfaceImplE_H
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef OHOS_HDI_NEARLINK_OFF_FIND_V1_0_REMOTE_DEATH_RECIPIENT_H
|
||||
#define OHOS_HDI_NEARLINK_OFF_FIND_V1_0_REMOTE_DEATH_RECIPIENT_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "iremote_object.h"
|
||||
#include "refbase.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace HDI {
|
||||
namespace Nearlink {
|
||||
namespace OffFind {
|
||||
namespace V1_0 {
|
||||
class RemoteDeathRecipient : public IRemoteObject::DeathRecipient {
|
||||
public:
|
||||
explicit RemoteDeathRecipient(std::function<void(const wptr<IRemoteObject> &)> callback)
|
||||
{
|
||||
callback_ = callback;
|
||||
}
|
||||
~RemoteDeathRecipient()
|
||||
{
|
||||
callback_ = nullptr;
|
||||
}
|
||||
|
||||
void OnRemoteDied(const wptr<IRemoteObject> &object)
|
||||
{
|
||||
if (callback_ != nullptr) {
|
||||
callback_(object);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(const wptr<IRemoteObject> &)> callback_;
|
||||
};
|
||||
} // namespace V1_0
|
||||
} // namespace OffFind
|
||||
} // namespace Nearlink
|
||||
} // namespace HDI
|
||||
} // OHOS
|
||||
|
||||
#endif // OHOS_HDI_NEARLINK_OFF_FIND_V1_0_REMOTE_DEATH_RECIPIENT_H
|
||||
Reference in New Issue
Block a user