* Copyright (C) 2025 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 LOG_TAG
#define LOG_TAG "bt_taihe_parser_utils"
#endif
#include "taihe_parser_utils.h"
#include "bluetooth_log.h"
#include "taihe_async_callback.h"
#include "taihe_bluetooth_utils.h"
#include "taihe/array.hpp"
#include "taihe/optional.hpp"
#include "taihe/platform/ani.hpp"
#include <string>
#include <vector>
namespace OHOS {
namespace Bluetooth {
TaiheStatus TaiheParseGattService(ohos::bluetooth::ble::GattService object, TaiheGattService &outService)
{
UUID uuid {};
bool isPrimary = true;
std::vector<TaiheBleCharacteristic> characteristics {};
TAIHE_BT_CALL_RETURN(ParseUuidParams(std::string(object.serviceUuid), uuid));
isPrimary = object.isPrimary;
taihe::array<ohos::bluetooth::ble::BLECharacteristic> objectCharacteristics = object.characteristics;
if (objectCharacteristics.size() > 0) {
TAIHE_BT_CALL_RETURN(TaiheParseGattCharacteristicVec(objectCharacteristics, characteristics));
}
if (object.includeServices.has_value()) {
taihe::array<ohos::bluetooth::ble::GattService> objectIncludeServices = object.includeServices.value();
if (objectIncludeServices.size() > 0) {
std::vector<TaiheGattService> includeServices {};
TAIHE_BT_CALL_RETURN(TaiheParseIncludeService(objectIncludeServices, includeServices));
outService.includeServices = std::move(includeServices);
}
}
outService.serviceUuid = uuid;
outService.isPrimary = isPrimary;
outService.characteristics = std::move(characteristics);
return TAIHE_OK;
}
namespace {
const TaiheGattPermission DEFAULT_GATT_PERMISSIONS = {
.readable = true,
.writeable = true,
};
const TaiheGattProperties DEFAULT_GATT_PROPERTIES = {
.write = true,
.writeNoResponse = true,
.read = true,
};
uint16_t ConvertGattPermissions(const TaiheGattPermission &taihePermissions)
{
uint16_t permissions = 0;
if (taihePermissions.readable) {
permissions |= static_cast<uint16_t>(GattPermission::READABLE);
}
if (taihePermissions.readEncrypted) {
permissions |= static_cast<uint16_t>(GattPermission::READ_ENCRYPTED);
}
if (taihePermissions.readEncryptedMitm) {
permissions |= static_cast<uint16_t>(GattPermission::READ_ENCRYPTED_MITM);
}
if (taihePermissions.writeable) {
permissions |= static_cast<uint16_t>(GattPermission::WRITEABLE);
}
if (taihePermissions.writeEncrypted) {
permissions |= static_cast<uint16_t>(GattPermission::WRITE_ENCRYPTED);
}
if (taihePermissions.writeEncryptedMitm) {
permissions |= static_cast<uint16_t>(GattPermission::WRITE_ENCRYPTED_MITM);
}
if (taihePermissions.writeSigned) {
permissions |= static_cast<uint16_t>(GattPermission::WRITE_SIGNED);
}
if (taihePermissions.writeSignedMitm) {
permissions |= static_cast<uint16_t>(GattPermission::WRITE_SIGNED_MITM);
}
return permissions;
}
uint16_t ConvertGattProperties(const TaiheGattProperties &taiheProperties)
{
uint16_t properties = 0;
if (taiheProperties.read) {
properties |= static_cast<uint16_t>(GattCharacteristic::READ);
}
if (taiheProperties.write) {
properties |= static_cast<uint16_t>(GattCharacteristic::WRITE);
}
if (taiheProperties.writeNoResponse) {
properties |= static_cast<uint16_t>(GattCharacteristic::WRITE_WITHOUT_RESPONSE);
}
if (taiheProperties.notify) {
properties |= static_cast<uint16_t>(GattCharacteristic::NOTIFY);
}
if (taiheProperties.indicate) {
properties |= static_cast<uint16_t>(GattCharacteristic::INDICATE);
}
if (taiheProperties.broadcast) {
properties |= static_cast<uint16_t>(GattCharacteristic::BROADCAST);
}
if (taiheProperties.authenticatedSignedWrite) {
properties |= static_cast<uint16_t>(GattCharacteristic::AUTHENTICATED_SIGNED_WRITES);
}
if (taiheProperties.extendedProperties) {
properties |= static_cast<uint16_t>(GattCharacteristic::EXTENDED_PROPERTIES);
}
return properties;
}
}
TaiheStatus TaiheParseIncludeService(taihe::array<ohos::bluetooth::ble::GattService> object,
std::vector<TaiheGattService> &outIncludeService)
{
for (size_t i = 0; i < object.size(); i++) {
ohos::bluetooth::ble::GattService element = object[i];
TaiheGattService includeService {};
TAIHE_BT_CALL_RETURN(TaiheParseGattService(element, includeService));
outIncludeService.push_back(std::move(includeService));
}
return TAIHE_OK;
}
TaiheStatus TaiheParseGattCharacteristicVec(taihe::array<ohos::bluetooth::ble::BLECharacteristic> object,
std::vector<TaiheBleCharacteristic> &outCharacteristic)
{
for (size_t i = 0; i < object.size(); i++) {
TaiheBleCharacteristic characteristic {};
TAIHE_BT_CALL_RETURN(TaiheParseGattCharacteristic(object[i], characteristic));
outCharacteristic.push_back(std::move(characteristic));
}
return TAIHE_OK;
}
TaiheStatus TaiheParseGattCharacteristic(ohos::bluetooth::ble::BLECharacteristic object,
TaiheBleCharacteristic &outCharacteristic)
{
TaiheBleCharacteristic characteristic {};
UUID serviceUuid {};
UUID characterUuid {};
std::vector<uint8_t> characterValue {};
std::vector<TaiheBleDescriptor> descriptors {};
uint32_t characteristicValueHandle = 0;
TaiheGattProperties properties = DEFAULT_GATT_PROPERTIES;
TaiheGattPermission permissions = DEFAULT_GATT_PERMISSIONS;
TAIHE_BT_CALL_RETURN(ParseUuidParams(std::string(object.serviceUuid), serviceUuid));
TAIHE_BT_CALL_RETURN(ParseUuidParams(std::string(object.characteristicUuid), characterUuid));
if (object.characteristicValue.size() > 0) {
ParseArrayBufferParams(object.characteristicValue, characterValue);
}
if (object.descriptors.size() > 0) {
taihe::array<ohos::bluetooth::ble::BLEDescriptor> objectDescriptors = object.descriptors;
TAIHE_BT_CALL_RETURN(TaiheParseGattDescriptorVec(objectDescriptors, descriptors));
}
if (object.properties.has_value()) {
ohos::bluetooth::ble::GattProperties objectProperties = object.properties.value();
TaiheParseObjectGattProperties(objectProperties, properties);
}
if (object.characteristicValueHandle.has_value()) {
characteristicValueHandle = object.characteristicValueHandle.value();
TAIHE_BT_RETURN_IF(characteristicValueHandle > 0xFFFF, "Invalid characteristicValueHandle",
TAIHE_INVALID_ARG);
}
if (object.permissions.has_value()) {
ohos::bluetooth::ble::GattPermissions objectPermissions = object.permissions.value();
TaiheParseObjectGattPermissions(objectPermissions, permissions);
}
outCharacteristic.serviceUuid = serviceUuid;
outCharacteristic.characteristicUuid = characterUuid;
outCharacteristic.characteristicValue = std::move(characterValue);
outCharacteristic.descriptors = std::move(descriptors);
outCharacteristic.properties = ConvertGattProperties(properties);
outCharacteristic.characteristicValueHandle = static_cast<uint16_t>(characteristicValueHandle);
outCharacteristic.permissions = ConvertGattPermissions(permissions);
return TAIHE_OK;
}
TaiheStatus TaiheParseGattDescriptorVec(taihe::array<ohos::bluetooth::ble::BLEDescriptor> object,
std::vector<TaiheBleDescriptor> &outDescriptor)
{
for (size_t i = 0; i < object.size(); i++) {
TaiheBleDescriptor descriptor {};
TAIHE_BT_CALL_RETURN(TaiheParseGattDescriptor(object[i], descriptor));
outDescriptor.push_back(std::move(descriptor));
}
return TAIHE_OK;
}
TaiheStatus TaiheParseGattDescriptor(ohos::bluetooth::ble::BLEDescriptor object,
TaiheBleDescriptor &outDescriptor)
{
UUID serviceUuid {};
UUID characterUuid {};
UUID descriptorUuid {};
std::vector<uint8_t> descriptorValue {};
uint32_t descriptorHandle = 0;
TaiheGattPermission permissions = DEFAULT_GATT_PERMISSIONS;
TAIHE_BT_CALL_RETURN(ParseUuidParams(std::string(object.serviceUuid), serviceUuid));
TAIHE_BT_CALL_RETURN(ParseUuidParams(std::string(object.characteristicUuid), characterUuid));
TAIHE_BT_CALL_RETURN(ParseUuidParams(std::string(object.descriptorUuid), descriptorUuid));
if (object.descriptorValue.size() > 0) {
ParseArrayBufferParams(object.descriptorValue, descriptorValue);
}
if (object.descriptorHandle.has_value()) {
descriptorHandle = object.descriptorHandle.value();
TAIHE_BT_RETURN_IF(descriptorHandle > 0xFFFF, "Invalid descriptorHandle", TAIHE_INVALID_ARG);
}
if (object.permissions.has_value()) {
ohos::bluetooth::ble::GattPermissions objectPermissions = object.permissions.value();
TaiheParseObjectGattPermissions(objectPermissions, permissions);
}
outDescriptor.serviceUuid = serviceUuid;
outDescriptor.characteristicUuid = characterUuid;
outDescriptor.descriptorUuid = descriptorUuid;
outDescriptor.descriptorValue = std::move(descriptorValue);
outDescriptor.descriptorHandle = static_cast<uint16_t>(descriptorHandle);
outDescriptor.permissions = ConvertGattPermissions(permissions);
return TAIHE_OK;
}
void TaiheParseObjectGattPermissions(ohos::bluetooth::ble::GattPermissions object,
TaiheGattPermission &outPermissions)
{
TaiheGattPermission permissions {};
if (object.read.has_value()) {
permissions.readable = object.read.value();
}
if (object.readEncrypted.has_value()) {
permissions.readEncrypted = object.readEncrypted.value();
}
if (object.readEncryptedMitm.has_value()) {
permissions.readEncryptedMitm = object.readEncryptedMitm.value();
}
if (object.write.has_value()) {
permissions.writeable = object.write.value();
}
if (object.writeEncrypted.has_value()) {
permissions.writeEncrypted = object.writeEncrypted.value();
}
if (object.writeEncryptedMitm.has_value()) {
permissions.writeEncryptedMitm = object.writeEncryptedMitm.value();
}
if (object.writeSigned.has_value()) {
permissions.writeSigned = object.writeSigned.value();
}
if (object.writeSignedMitm.has_value()) {
permissions.writeSignedMitm = object.writeSignedMitm.value();
}
outPermissions = permissions;
}
void TaiheParseObjectGattProperties(ohos::bluetooth::ble::GattProperties object,
TaiheGattProperties &outProperties)
{
TaiheGattProperties properties {};
if (object.write.has_value()) {
properties.write = object.write.value();
}
if (object.writeNoResponse.has_value()) {
properties.writeNoResponse = object.writeNoResponse.value();
}
if (object.read.has_value()) {
properties.read = object.read.value();
}
if (object.notify.has_value()) {
properties.notify = object.notify.value();
}
if (object.indicate.has_value()) {
properties.indicate = object.indicate.value();
}
if (object.broadcast.has_value()) {
properties.broadcast = object.broadcast.value();
}
if (object.authenticatedSignedWrite.has_value()) {
properties.authenticatedSignedWrite = object.authenticatedSignedWrite.value();
}
if (object.extendedProperties.has_value()) {
properties.extendedProperties = object.extendedProperties.value();
}
outProperties = properties;
}
TaiheStatus TaiheParseNotifyCharacteristic(ohos::bluetooth::ble::NotifyCharacteristic object,
TaiheNotifyCharacteristic &outCharacter)
{
UUID serviceUuid {};
UUID characterUuid {};
std::vector<uint8_t> characterValue {};
bool confirm = false;
TAIHE_BT_CALL_RETURN(ParseUuidParams(std::string(object.serviceUuid), serviceUuid));
TAIHE_BT_CALL_RETURN(ParseUuidParams(std::string(object.characteristicUuid), characterUuid));
ParseArrayBufferParams(object.characteristicValue, characterValue);
confirm = object.confirm;
outCharacter.serviceUuid = serviceUuid;
outCharacter.characterUuid = characterUuid;
outCharacter.characterValue = std::move(characterValue);
outCharacter.confirm = confirm;
return TAIHE_OK;
}
std::shared_ptr<TaiheAsyncCallback> TaiheParseAsyncCallback(ani_env *env, ani_object info)
{
ani_vm *vm = nullptr;
if (env == nullptr) {
HILOGE("null env");
return nullptr;
}
if (ANI_OK != env->GetVM(&vm)) {
HILOGE("GetVM failed");
return nullptr;
}
auto asyncCallback = std::make_shared<TaiheAsyncCallback>();
asyncCallback->env = env;
if (info != nullptr) {
HILOGD("callback mode");
asyncCallback->callback = std::make_shared<TaiheCallback>(vm, info);
} else {
HILOGD("promise mode");
asyncCallback->promise = std::make_shared<TaihePromise>(vm);
}
return asyncCallback;
}
}
}