mirror of
https://github.com/switchbrew/libnx.git
synced 2025-07-04 02:22:15 +02:00
Added btdev.
This commit is contained in:
parent
a02f554eba
commit
6ab0dc38e6
@ -154,6 +154,7 @@ extern "C" {
|
|||||||
#include "switch/runtime/nxlink.h"
|
#include "switch/runtime/nxlink.h"
|
||||||
#include "switch/runtime/resolver.h"
|
#include "switch/runtime/resolver.h"
|
||||||
#include "switch/runtime/ringcon.h"
|
#include "switch/runtime/ringcon.h"
|
||||||
|
#include "switch/runtime/btdev.h"
|
||||||
|
|
||||||
#include "switch/runtime/util/utf.h"
|
#include "switch/runtime/util/utf.h"
|
||||||
|
|
||||||
|
267
nx/include/switch/runtime/btdev.h
Normal file
267
nx/include/switch/runtime/btdev.h
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
/**
|
||||||
|
* @file btdev.h
|
||||||
|
* @brief Wrapper around the bt/btmu services for using bluetooth BLE.
|
||||||
|
* @author yellows8
|
||||||
|
* @copyright libnx Authors
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "../types.h"
|
||||||
|
#include "../kernel/event.h"
|
||||||
|
#include "../services/btdrv_types.h"
|
||||||
|
|
||||||
|
/// GattAttribute
|
||||||
|
typedef struct {
|
||||||
|
u8 type; ///< Type
|
||||||
|
BtdrvGattAttributeUuid uuid; ///< \ref BtdrvGattAttributeUuid
|
||||||
|
u16 handle; ///< Handle
|
||||||
|
u32 connection_handle; ///< ConnectionHandle
|
||||||
|
} BtdevGattAttribute;
|
||||||
|
|
||||||
|
/// GattService
|
||||||
|
typedef struct {
|
||||||
|
BtdevGattAttribute attr; ///< \ref BtdevGattAttribute
|
||||||
|
u16 instance_id; ///< InstanceId
|
||||||
|
u16 end_group_handle; ///< EndGroupHandle
|
||||||
|
bool primary_service; ///< PrimaryService
|
||||||
|
} BtdevGattService;
|
||||||
|
|
||||||
|
/// GattCharacteristic
|
||||||
|
typedef struct {
|
||||||
|
BtdevGattAttribute attr; ///< \ref BtdevGattAttribute
|
||||||
|
u16 instance_id; ///< InstanceId
|
||||||
|
u8 properties; ///< Properties
|
||||||
|
u64 value_size; ///< Size of value.
|
||||||
|
u8 value[0x200]; ///< Value
|
||||||
|
} BtdevGattCharacteristic;
|
||||||
|
|
||||||
|
/// GattDescriptor
|
||||||
|
typedef struct {
|
||||||
|
BtdevGattAttribute attr; ///< \ref BtdevGattAttribute
|
||||||
|
u64 value_size; ///< Size of value.
|
||||||
|
u8 value[0x200]; ///< Value
|
||||||
|
} BtdevGattDescriptor;
|
||||||
|
|
||||||
|
/// Initialize bt/btmu.
|
||||||
|
Result btdevInitialize(void);
|
||||||
|
|
||||||
|
/// Exit bt/btmu.
|
||||||
|
void btdevExit(void);
|
||||||
|
|
||||||
|
/// Compares two \ref BtdrvGattAttributeUuid, returning whether these match.
|
||||||
|
bool btdevGattAttributeUuidIsSame(const BtdrvGattAttributeUuid *a, const BtdrvGattAttributeUuid *b);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuAcquireBleScanEvent.
|
||||||
|
Result btdevAcquireBleScanEvent(Event* out_event);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetBleScanFilterParameter.
|
||||||
|
Result btdevGetBleScanParameter(u16 unk, BtdrvBleAdvertisePacketParameter *out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetBleScanFilterParameter2.
|
||||||
|
Result btdevGetBleScanParameter2(u16 unk, BtdrvGattAttributeUuid *out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btdevStartBleScanGeneral.
|
||||||
|
Result btdevStartBleScanGeneral(BtdrvBleAdvertisePacketParameter param);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuStopBleScanForGeneral.
|
||||||
|
Result btdevStopBleScanGeneral(void);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetBleScanResultsForGeneral and \ref btmuGetBleScanResultsForSmartDevice.
|
||||||
|
Result btdevGetBleScanResult(BtdrvBleScanResult *results, u8 count, u8 *total_out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuStartBleScanForPaired.
|
||||||
|
Result btdevEnableBleAutoConnection(BtdrvBleAdvertisePacketParameter param);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuStopBleScanForPaired.
|
||||||
|
Result btdevDisableBleAutoConnection(void);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuStartBleScanForSmartDevice.
|
||||||
|
Result btdevStartBleScanSmartDevice(const BtdrvGattAttributeUuid *uuid);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuStopBleScanForSmartDevice.
|
||||||
|
Result btdevStopBleScanSmartDevice(void);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuAcquireBleConnectionEvent.
|
||||||
|
Result btdevAcquireBleConnectionStateChangedEvent(Event* out_event);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuBleConnect.
|
||||||
|
Result btdevConnectToGattServer(BtdrvAddress addr);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuBleDisconnect.
|
||||||
|
Result btdevDisconnectFromGattServer(u32 id);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuBleGetConnectionState.
|
||||||
|
Result btdevGetBleConnectionInfoList(BtdrvBleConnectionInfo *info, u8 count, u8 *total_out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuAcquireBleServiceDiscoveryEvent.
|
||||||
|
Result btdevAcquireBleServiceDiscoveryEvent(Event* out_event);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetGattServices.
|
||||||
|
Result btdevGetGattServices(u32 connection_handle, BtdevGattService *services, u8 count, u8 *total_out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetGattService.
|
||||||
|
Result btdevGetGattService(u32 connection_handle, const BtdrvGattAttributeUuid *uuid, BtdevGattService *service, bool *flag);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuAcquireBlePairingEvent.
|
||||||
|
Result btdevAcquireBlePairingEvent(Event* out_event);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuBlePairDevice.
|
||||||
|
Result btdevPairGattServer(BtdrvBleAdvertisePacketParameter param, u32 id);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuBleUnPairDevice.
|
||||||
|
Result btdevUnpairGattServer(BtdrvBleAdvertisePacketParameter param, u32 id);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuBleUnPairDevice2.
|
||||||
|
Result btdevUnpairGattServer2(BtdrvAddress addr, BtdrvBleAdvertisePacketParameter param);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuBleGetPairedDevices.
|
||||||
|
Result btdevGetPairedGattServerAddress(BtdrvBleAdvertisePacketParameter param, BtdrvAddress *addrs, u8 count, u8 *total_out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuAcquireBleMtuConfigEvent.
|
||||||
|
Result btdevAcquireBleMtuConfigEvent(Event* out_event);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuConfigureBleMtu. mtu must be 0x18-0x200.
|
||||||
|
Result btdevConfigureBleMtu(u32 id, u16 mtu);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetBleMtu.
|
||||||
|
Result btdevGetBleMtu(u32 id, u16 *out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btRegisterBleEvent.
|
||||||
|
Result btdevAcquireBleGattOperationEvent(Event* out_event);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btdevRegisterGattOperationNotification.
|
||||||
|
Result btdevRegisterGattOperationNotification(const BtdrvGattAttributeUuid *uuid);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btdevUnregisterGattOperationNotification.
|
||||||
|
Result btdevUnregisterGattOperationNotification(const BtdrvGattAttributeUuid *uuid);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btGetLeEventInfo.
|
||||||
|
Result btdevGetGattOperationResult(BtdrvBleClientGattOperationInfo *out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btLeClientReadCharacteristic.
|
||||||
|
Result btdevReadGattCharacteristic(BtdevGattCharacteristic *c);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btLeClientWriteCharacteristic.
|
||||||
|
Result btdevWriteGattCharacteristic(BtdevGattCharacteristic *c);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btLeClientRegisterNotification / \ref btLeClientDeregisterNotification, flag controls which func to call.
|
||||||
|
Result btdevEnableGattCharacteristicNotification(BtdevGattCharacteristic *c, bool flag);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btLeClientReadDescriptor.
|
||||||
|
Result btdevReadGattDescriptor(BtdevGattDescriptor *d);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btLeClientWriteDescriptor.
|
||||||
|
Result btdevWriteGattDescriptor(BtdevGattDescriptor *d);
|
||||||
|
|
||||||
|
///@name GattAttribute
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Creates a \ref BtdevGattAttribute object.
|
||||||
|
void btdevGattAttributeCreate(BtdevGattAttribute *a, const BtdrvGattAttributeUuid *uuid, u16 handle, u32 connection_handle);
|
||||||
|
|
||||||
|
/// Gets the Type.
|
||||||
|
NX_CONSTEXPR u8 btdevGattAttributeGetType(BtdevGattAttribute *a) {
|
||||||
|
return a->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the Uuid.
|
||||||
|
NX_CONSTEXPR void btdevGattAttributeGetUuid(BtdevGattAttribute *a, BtdrvGattAttributeUuid *out) {
|
||||||
|
*out = a->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the Handle.
|
||||||
|
NX_CONSTEXPR u16 btdevGattAttributeGetHandle(BtdevGattAttribute *a) {
|
||||||
|
return a->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the ConnectionHandle.
|
||||||
|
NX_CONSTEXPR u32 btdevGattAttributeGetConnectionHandle(BtdevGattAttribute *a) {
|
||||||
|
return a->connection_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
///@name GattService
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Creates a \ref BtdevGattService object.
|
||||||
|
void btdevGattServiceCreate(BtdevGattService *s, const BtdrvGattAttributeUuid *uuid, u16 handle, u32 connection_handle, u16 instance_id, u16 end_group_handle, bool primary_service);
|
||||||
|
|
||||||
|
/// Gets the InstanceId.
|
||||||
|
NX_CONSTEXPR u16 btdevGattServiceGetInstanceId(BtdevGattService *s) {
|
||||||
|
return s->instance_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the EndGroupHandle.
|
||||||
|
NX_CONSTEXPR u16 btdevGattServiceGetEndGroupHandle(BtdevGattService *s) {
|
||||||
|
return s->end_group_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets whether this is the PrimaryService.
|
||||||
|
NX_CONSTEXPR u16 btdevGattServiceIsPrimaryService(BtdevGattService *s) {
|
||||||
|
return s->primary_service;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetGattIncludedServices.
|
||||||
|
Result btdevGattServiceGetIncludedServices(BtdevGattService *s, BtdevGattService *services, u8 count, u8 *total_out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetGattCharacteristics.
|
||||||
|
Result btdevGattServiceGetCharacteristics(BtdevGattService *s, BtdevGattCharacteristic *characteristic, u8 count, u8 *total_out);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetGattCharacteristics.
|
||||||
|
Result btdevGattServiceGetCharacteristic(BtdevGattService *s, const BtdrvGattAttributeUuid *uuid, BtdevGattCharacteristic *characteristic, bool *flag);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
///@name GattCharacteristic
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Creates a \ref BtdevGattCharacteristic object.
|
||||||
|
void btdevGattCharacteristicCreate(BtdevGattCharacteristic *c, const BtdrvGattAttributeUuid *uuid, u16 handle, u32 connection_handle, u16 instance_id, u8 properties);
|
||||||
|
|
||||||
|
/// Gets the InstanceId.
|
||||||
|
NX_CONSTEXPR u16 btdevGattCharacteristicGetInstanceId(BtdevGattCharacteristic *c) {
|
||||||
|
return c->instance_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the Properties.
|
||||||
|
NX_CONSTEXPR u8 btdevGattCharacteristicGetProperties(BtdevGattCharacteristic *c) {
|
||||||
|
return c->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetBelongingGattService.
|
||||||
|
Result btdevGattCharacteristicGetService(BtdevGattCharacteristic *c, BtdevGattService *service);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetGattDescriptors.
|
||||||
|
Result btdevGattCharacteristicGetDescriptors(BtdevGattCharacteristic *c, BtdevGattDescriptor *descriptors, u8 count, u8 *total_out);
|
||||||
|
|
||||||
|
/// Same as \ref btdevGattCharacteristicGetDescriptors except this only returns a \ref BtdevGattDescriptor which contains a matching \ref BtdrvGattAttributeUuid.
|
||||||
|
Result btdevGattCharacteristicGetDescriptor(BtdevGattCharacteristic *c, const BtdrvGattAttributeUuid *uuid, BtdevGattDescriptor *descriptor, bool *flag);
|
||||||
|
|
||||||
|
/// Sets the Value in the object, max size is 0x200.
|
||||||
|
void btdevGattCharacteristicSetValue(BtdevGattCharacteristic *c, const void* buffer, size_t size);
|
||||||
|
|
||||||
|
/// Gets the Value in the object, returns the copied value size.
|
||||||
|
u64 btdevGattCharacteristicGetValue(BtdevGattCharacteristic *c, void* buffer, size_t size);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
///@name GattDescriptor
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Creates a \ref BtdevGattDescriptor object.
|
||||||
|
void btdevGattDescriptorCreate(BtdevGattDescriptor *d, const BtdrvGattAttributeUuid *uuid, u16 handle, u32 connection_handle);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetBelongingGattService.
|
||||||
|
Result btdevGattDescriptorGetService(BtdevGattDescriptor *d, BtdevGattService *service);
|
||||||
|
|
||||||
|
/// Wrapper for \ref btmuGetGattCharacteristics.
|
||||||
|
Result btdevGattDescriptorGetCharacteristic(BtdevGattDescriptor *d, BtdevGattCharacteristic *characteristic);
|
||||||
|
|
||||||
|
/// Sets the Value in the object, max size is 0x200.
|
||||||
|
void btdevGattDescriptorSetValue(BtdevGattDescriptor *d, const void* buffer, size_t size);
|
||||||
|
|
||||||
|
/// Gets the Value in the object, returns the copied value size.
|
||||||
|
u64 btdevGattDescriptorGetValue(BtdevGattDescriptor *d, void* buffer, size_t size);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
613
nx/source/runtime/btdev.c
Normal file
613
nx/source/runtime/btdev.c
Normal file
@ -0,0 +1,613 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "runtime/btdev.h"
|
||||||
|
#include "services/bt.h"
|
||||||
|
#include "services/btmu.h"
|
||||||
|
|
||||||
|
Result btdevInitialize(void) {
|
||||||
|
Result rc=0;
|
||||||
|
|
||||||
|
rc = btInitialize();
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
rc = btmuInitialize();
|
||||||
|
if (R_FAILED(rc)) btExit();
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void btdevExit(void) {
|
||||||
|
btmuExit();
|
||||||
|
btExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// sdknso does Result error-conversion, but we won't do so.
|
||||||
|
|
||||||
|
bool btdevGattAttributeUuidIsSame(const BtdrvGattAttributeUuid *a, const BtdrvGattAttributeUuid *b) {
|
||||||
|
if (a->size != b->size) return false;
|
||||||
|
if (a->size != 0x2 && a->size != 0x4 && a->size != 0x10) return false;
|
||||||
|
return memcmp(a->uuid, b->uuid, a->size)==0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevAcquireBleScanEvent(Event* out_event) {
|
||||||
|
return btmuAcquireBleScanEvent(out_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetBleScanParameter(u16 unk, BtdrvBleAdvertisePacketParameter *out) {
|
||||||
|
return btmuGetBleScanFilterParameter(unk, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetBleScanParameter2(u16 unk, BtdrvGattAttributeUuid *out) {
|
||||||
|
return btmuGetBleScanFilterParameter2(unk, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevStartBleScanGeneral(BtdrvBleAdvertisePacketParameter param) {
|
||||||
|
return btmuStartBleScanForGeneral(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevStopBleScanGeneral(void) {
|
||||||
|
return btmuStopBleScanForGeneral();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetBleScanResult(BtdrvBleScanResult *results, u8 count, u8 *total_out) {
|
||||||
|
Result rc=0;
|
||||||
|
BtdrvBleScanResult tmpresults[2][10]={0};
|
||||||
|
u8 tmp_total_out[2]={0};
|
||||||
|
u8 tmpi[2]={0};
|
||||||
|
u8 targeti=0;
|
||||||
|
|
||||||
|
memset(results, 0, sizeof(BtdrvBleScanResult)*count);
|
||||||
|
|
||||||
|
rc = btmuGetBleScanResultsForGeneral(tmpresults[0], 10, &tmp_total_out[0]);
|
||||||
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
|
rc = btmuGetBleScanResultsForSmartDevice(tmpresults[1], 10, &tmp_total_out[1]);
|
||||||
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
|
for (u8 i=0; i<count; i++) {
|
||||||
|
if (tmpi[0] < tmp_total_out[0] && tmpi[1] < tmp_total_out[1]) {
|
||||||
|
if (tmpresults[0][tmpi[0]].unk_x144 >= tmpresults[1][tmpi[1]].unk_x144) targeti = 0;
|
||||||
|
else targeti = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (tmpi[1] >= tmp_total_out[1] && tmpi[0] < tmp_total_out[0]) targeti = 0;
|
||||||
|
else if (tmpi[0] >= tmp_total_out[0] && tmpi[1] < tmp_total_out[1]) targeti = 1;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(results, &tmpresults[targeti][tmpi[targeti]], sizeof(BtdrvBleScanResult));
|
||||||
|
results++;
|
||||||
|
tmpi[targeti]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_out) *total_out = tmpi[0] + tmpi[1];
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevEnableBleAutoConnection(BtdrvBleAdvertisePacketParameter param) {
|
||||||
|
return btmuStartBleScanForPaired(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevDisableBleAutoConnection(void) {
|
||||||
|
return btmuStopBleScanForPaired();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevStartBleScanSmartDevice(const BtdrvGattAttributeUuid *uuid) {
|
||||||
|
return btmuStartBleScanForSmartDevice(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevStopBleScanSmartDevice(void) {
|
||||||
|
return btmuStopBleScanForSmartDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevAcquireBleConnectionStateChangedEvent(Event* out_event) {
|
||||||
|
return btmuAcquireBleConnectionEvent(out_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevConnectToGattServer(BtdrvAddress addr) {
|
||||||
|
return btmuBleConnect(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevDisconnectFromGattServer(u32 id) {
|
||||||
|
return btmuBleDisconnect(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetBleConnectionInfoList(BtdrvBleConnectionInfo *info, u8 count, u8 *total_out) {
|
||||||
|
return btmuBleGetConnectionState(info, count, total_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevAcquireBleServiceDiscoveryEvent(Event* out_event) {
|
||||||
|
return btmuAcquireBleServiceDiscoveryEvent(out_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetGattServices(u32 connection_handle, BtdevGattService *services, u8 count, u8 *total_out) {
|
||||||
|
Result rc=0;
|
||||||
|
u8 tmp_total_out=0;
|
||||||
|
BtmGattService tmpservices[100]={0};
|
||||||
|
|
||||||
|
memset(services, 0, sizeof(BtdevGattService)*count);
|
||||||
|
|
||||||
|
rc = btmuGetGattServices(connection_handle, tmpservices, 100, &tmp_total_out);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmp_total_out > count) tmp_total_out = count;
|
||||||
|
for (u8 i=0; i<tmp_total_out; i++) {
|
||||||
|
btdevGattServiceCreate(&services[i], &tmpservices[i].uuid, tmpservices[i].handle, connection_handle, tmpservices[i].instance_id, tmpservices[i].end_group_handle, tmpservices[i].primary_service);
|
||||||
|
}
|
||||||
|
if (total_out) *total_out = tmp_total_out;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetGattService(u32 connection_handle, const BtdrvGattAttributeUuid *uuid, BtdevGattService *service, bool *flag) {
|
||||||
|
Result rc=0;
|
||||||
|
bool tmp_flag=0;
|
||||||
|
BtmGattService tmpservice={0};
|
||||||
|
|
||||||
|
memset(service, 0, sizeof(BtdevGattService));
|
||||||
|
|
||||||
|
rc = btmuGetGattService(connection_handle, uuid, &tmpservice, &tmp_flag);
|
||||||
|
if (R_SUCCEEDED(rc) && tmp_flag) {
|
||||||
|
btdevGattServiceCreate(service, uuid, tmpservice.handle, connection_handle, tmpservice.instance_id, tmpservice.end_group_handle, tmpservice.primary_service);
|
||||||
|
}
|
||||||
|
if (R_SUCCEEDED(rc) && flag) *flag = tmp_flag;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevAcquireBlePairingEvent(Event* out_event) {
|
||||||
|
return btmuAcquireBlePairingEvent(out_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevPairGattServer(BtdrvBleAdvertisePacketParameter param, u32 id) {
|
||||||
|
return btmuBlePairDevice(param, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevUnpairGattServer(BtdrvBleAdvertisePacketParameter param, u32 id) {
|
||||||
|
return btmuBleUnPairDevice(param, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevUnpairGattServer2(BtdrvAddress addr, BtdrvBleAdvertisePacketParameter param) {
|
||||||
|
return btmuBleUnPairDevice2(addr, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetPairedGattServerAddress(BtdrvBleAdvertisePacketParameter param, BtdrvAddress *addrs, u8 count, u8 *total_out) {
|
||||||
|
return btmuBleGetPairedDevices(param, addrs, count, total_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevAcquireBleMtuConfigEvent(Event* out_event) {
|
||||||
|
return btmuAcquireBleMtuConfigEvent(out_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevConfigureBleMtu(u32 id, u16 mtu) {
|
||||||
|
if (mtu < 0x18 || mtu > 0x200) return MAKERESULT(Module_Libnx, LibnxError_BadInput); // sdknso would Abort here, sdknso impls the same thing in the btmu func as well (but we don't).
|
||||||
|
return btmuConfigureBleMtu(id, mtu);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetBleMtu(u32 id, u16 *out) {
|
||||||
|
return btmuGetBleMtu(id, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevAcquireBleGattOperationEvent(Event* out_event) {
|
||||||
|
return btRegisterBleEvent(out_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevRegisterGattOperationNotification(const BtdrvGattAttributeUuid *uuid) {
|
||||||
|
BtmBleDataPath path = {.unk_x0 = 0, .uuid = *uuid};
|
||||||
|
return btmuRegisterBleGattDataPath(&path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevUnregisterGattOperationNotification(const BtdrvGattAttributeUuid *uuid) {
|
||||||
|
BtmBleDataPath path = {.unk_x0 = 0, .uuid = *uuid};
|
||||||
|
return btmuUnregisterBleGattDataPath(&path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGetGattOperationResult(BtdrvBleClientGattOperationInfo *out) {
|
||||||
|
Result rc=0;
|
||||||
|
u32 type=0;
|
||||||
|
u8 tmpval=0;
|
||||||
|
BtdrvLeEventInfo eventinfo={0};
|
||||||
|
|
||||||
|
if (out==NULL) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||||
|
memset(out, 0, sizeof(*out));
|
||||||
|
|
||||||
|
rc = btGetLeEventInfo(&eventinfo, sizeof(eventinfo), &type);
|
||||||
|
if (R_SUCCEEDED(rc) && type!=8) rc = MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
switch(eventinfo.unk_x0) {
|
||||||
|
case 0:
|
||||||
|
tmpval=0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
case 16:
|
||||||
|
case 21:
|
||||||
|
case 50:
|
||||||
|
tmpval=3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
tmpval=4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
tmpval=5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
tmpval=6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9:
|
||||||
|
tmpval=7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13:
|
||||||
|
tmpval=8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 25:
|
||||||
|
case 52:
|
||||||
|
tmpval=2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 35:
|
||||||
|
tmpval=10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 55:
|
||||||
|
tmpval=1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
tmpval=9;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->unk_x0 = tmpval;
|
||||||
|
out->unk_x4 = eventinfo.unk_x4;
|
||||||
|
out->unk_x8 = eventinfo.unk_x8;
|
||||||
|
out->uuid0 = eventinfo.uuid0;
|
||||||
|
out->uuid1 = eventinfo.uuid1;
|
||||||
|
out->uuid2 = eventinfo.uuid2;
|
||||||
|
|
||||||
|
out->size = eventinfo.size;
|
||||||
|
if (out->size > sizeof(out->data)) out->size = sizeof(out->data);
|
||||||
|
memcpy(out->data, eventinfo.data, out->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevReadGattCharacteristic(BtdevGattCharacteristic *c) {
|
||||||
|
Result rc=0;
|
||||||
|
BtdevGattService tmpservice={0};
|
||||||
|
BtdrvGattId gattid0={0};
|
||||||
|
BtdrvGattId gattid1={0};
|
||||||
|
|
||||||
|
if ((btdevGattCharacteristicGetProperties(c) & BIT(1)) == 0)
|
||||||
|
rc = MAKERESULT(113, 523);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = btdevGattCharacteristicGetService(c, &tmpservice);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
gattid0.instance_id = btdevGattServiceGetInstanceId(&tmpservice);
|
||||||
|
btdevGattAttributeGetUuid(&tmpservice.attr, &gattid0.uuid);
|
||||||
|
gattid1.instance_id = btdevGattCharacteristicGetInstanceId(c);
|
||||||
|
btdevGattAttributeGetUuid(&c->attr, &gattid1.uuid);
|
||||||
|
rc = btLeClientReadCharacteristic(btdevGattServiceIsPrimaryService(&tmpservice), 0, btdevGattAttributeGetConnectionHandle(&c->attr), &gattid0, &gattid1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevWriteGattCharacteristic(BtdevGattCharacteristic *c) {
|
||||||
|
Result rc=0;
|
||||||
|
BtdevGattService tmpservice={0};
|
||||||
|
BtdrvGattId gattid0={0};
|
||||||
|
BtdrvGattId gattid1={0};
|
||||||
|
u8 prop = btdevGattCharacteristicGetProperties(c);
|
||||||
|
u64 value_size=0;
|
||||||
|
u8 value[0x200]={0};
|
||||||
|
|
||||||
|
if ((prop & (BIT(2) | BIT(3))) == 0)
|
||||||
|
rc = MAKERESULT(113, 523);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) value_size = btdevGattCharacteristicGetValue(c, value, sizeof(value));
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = btdevGattCharacteristicGetService(c, &tmpservice);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
gattid0.instance_id = btdevGattServiceGetInstanceId(&tmpservice);
|
||||||
|
btdevGattAttributeGetUuid(&tmpservice.attr, &gattid0.uuid);
|
||||||
|
gattid1.instance_id = btdevGattCharacteristicGetInstanceId(c);
|
||||||
|
btdevGattAttributeGetUuid(&c->attr, &gattid1.uuid);
|
||||||
|
rc = btLeClientWriteCharacteristic(btdevGattServiceIsPrimaryService(&tmpservice), 0, (prop & BIT(3)) != 0, btdevGattAttributeGetConnectionHandle(&c->attr), &gattid0, &gattid1, value, value_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevEnableGattCharacteristicNotification(BtdevGattCharacteristic *c, bool flag) {
|
||||||
|
Result rc=0;
|
||||||
|
BtdevGattService tmpservice={0};
|
||||||
|
BtdrvGattId gattid0={0};
|
||||||
|
BtdrvGattId gattid1={0};
|
||||||
|
u32 connection_handle = btdevGattAttributeGetConnectionHandle(&c->attr);
|
||||||
|
|
||||||
|
if ((btdevGattCharacteristicGetProperties(c) & (BIT(4) | BIT(5))) == 0)
|
||||||
|
rc = MAKERESULT(113, 523);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = btdevGattCharacteristicGetService(c, &tmpservice);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
gattid0.instance_id = btdevGattServiceGetInstanceId(&tmpservice);
|
||||||
|
btdevGattAttributeGetUuid(&tmpservice.attr, &gattid0.uuid);
|
||||||
|
gattid1.instance_id = btdevGattCharacteristicGetInstanceId(c);
|
||||||
|
btdevGattAttributeGetUuid(&c->attr, &gattid1.uuid);
|
||||||
|
bool is_primary = btdevGattServiceIsPrimaryService(&tmpservice);
|
||||||
|
if (flag)
|
||||||
|
rc = btLeClientRegisterNotification(is_primary, connection_handle, &gattid0, &gattid1);
|
||||||
|
else
|
||||||
|
rc = btLeClientDeregisterNotification(is_primary, connection_handle, &gattid0, &gattid1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevReadGattDescriptor(BtdevGattDescriptor *d) {
|
||||||
|
Result rc=0;
|
||||||
|
BtdevGattService tmpservice={0};
|
||||||
|
BtdevGattCharacteristic tmpcharacteristic={0};
|
||||||
|
BtdrvGattId gattid0={0};
|
||||||
|
BtdrvGattId gattid1={0};
|
||||||
|
BtdrvGattId gattid2={0}; // instance_id is left at 0.
|
||||||
|
|
||||||
|
rc = btdevGattDescriptorGetService(d, &tmpservice);
|
||||||
|
if (R_SUCCEEDED(rc)) rc = btdevGattDescriptorGetCharacteristic(d, &tmpcharacteristic);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
gattid0.instance_id = btdevGattServiceGetInstanceId(&tmpservice);
|
||||||
|
btdevGattAttributeGetUuid(&tmpservice.attr, &gattid0.uuid);
|
||||||
|
gattid1.instance_id = btdevGattCharacteristicGetInstanceId(&tmpcharacteristic);
|
||||||
|
btdevGattAttributeGetUuid(&tmpcharacteristic.attr, &gattid1.uuid);
|
||||||
|
btdevGattAttributeGetUuid(&d->attr, &gattid2.uuid);
|
||||||
|
rc = btLeClientReadDescriptor(btdevGattServiceIsPrimaryService(&tmpservice), 0, btdevGattAttributeGetConnectionHandle(&d->attr), &gattid0, &gattid1, &gattid2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevWriteGattDescriptor(BtdevGattDescriptor *d) {
|
||||||
|
Result rc=0;
|
||||||
|
BtdevGattService tmpservice={0};
|
||||||
|
BtdevGattCharacteristic tmpcharacteristic={0};
|
||||||
|
BtdrvGattId gattid0={0};
|
||||||
|
BtdrvGattId gattid1={0};
|
||||||
|
BtdrvGattId gattid2={0}; // instance_id is left at 0.
|
||||||
|
u64 value_size=0;
|
||||||
|
u8 value[0x200]={0};
|
||||||
|
|
||||||
|
value_size = btdevGattDescriptorGetValue(d, value, sizeof(value));
|
||||||
|
|
||||||
|
rc = btdevGattDescriptorGetService(d, &tmpservice);
|
||||||
|
if (R_SUCCEEDED(rc)) rc = btdevGattDescriptorGetCharacteristic(d, &tmpcharacteristic);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
gattid0.instance_id = btdevGattServiceGetInstanceId(&tmpservice);
|
||||||
|
btdevGattAttributeGetUuid(&tmpservice.attr, &gattid0.uuid);
|
||||||
|
gattid1.instance_id = btdevGattCharacteristicGetInstanceId(&tmpcharacteristic);
|
||||||
|
btdevGattAttributeGetUuid(&tmpcharacteristic.attr, &gattid1.uuid);
|
||||||
|
btdevGattAttributeGetUuid(&d->attr, &gattid2.uuid);
|
||||||
|
rc = btLeClientWriteDescriptor(btdevGattServiceIsPrimaryService(&tmpservice), 0, btdevGattAttributeGetConnectionHandle(&d->attr), &gattid0, &gattid1, &gattid2, value, value_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GattAttribute
|
||||||
|
|
||||||
|
void btdevGattAttributeCreate(BtdevGattAttribute *a, const BtdrvGattAttributeUuid *uuid, u16 handle, u32 connection_handle) {
|
||||||
|
memset(a, 0, sizeof(*a));
|
||||||
|
a->type = 0xff;
|
||||||
|
a->uuid = *uuid;
|
||||||
|
a->handle = handle;
|
||||||
|
a->connection_handle = connection_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GattService
|
||||||
|
|
||||||
|
void btdevGattServiceCreate(BtdevGattService *s, const BtdrvGattAttributeUuid *uuid, u16 handle, u32 connection_handle, u16 instance_id, u16 end_group_handle, bool primary_service) {
|
||||||
|
memset(s, 0, sizeof(*s));
|
||||||
|
btdevGattAttributeCreate(&s->attr, uuid, handle, connection_handle);
|
||||||
|
s->attr.type = 0x3;
|
||||||
|
s->instance_id = instance_id;
|
||||||
|
s->end_group_handle = end_group_handle;
|
||||||
|
s->primary_service = primary_service;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGattServiceGetIncludedServices(BtdevGattService *s, BtdevGattService *services, u8 count, u8 *total_out) {
|
||||||
|
Result rc=0;
|
||||||
|
u8 tmp_total_out=0;
|
||||||
|
BtmGattService tmpservices[100]={0};
|
||||||
|
|
||||||
|
memset(services, 0, sizeof(BtdevGattService)*count);
|
||||||
|
|
||||||
|
rc = btmuGetGattIncludedServices(s->attr.connection_handle, s->attr.handle, tmpservices, 100, &tmp_total_out);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmp_total_out > count) tmp_total_out = count;
|
||||||
|
for (u8 i=0; i<tmp_total_out; i++) {
|
||||||
|
btdevGattServiceCreate(&services[i], &tmpservices[i].uuid, tmpservices[i].handle, s->attr.connection_handle, tmpservices[i].instance_id, tmpservices[i].end_group_handle, tmpservices[i].primary_service);
|
||||||
|
}
|
||||||
|
if (total_out) *total_out = tmp_total_out;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGattServiceGetCharacteristics(BtdevGattService *s, BtdevGattCharacteristic *characteristic, u8 count, u8 *total_out) {
|
||||||
|
Result rc=0;
|
||||||
|
BtmGattCharacteristic tmpcharacteristics[100]={0};
|
||||||
|
u8 tmp_total_out=0;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = btmuGetGattCharacteristics(s->attr.connection_handle, s->attr.handle, tmpcharacteristics, 100, &tmp_total_out);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmp_total_out > count) tmp_total_out = count;
|
||||||
|
for (u8 i=0; i<tmp_total_out; i++) {
|
||||||
|
btdevGattCharacteristicCreate(characteristic, &tmpcharacteristics[i].uuid, tmpcharacteristics[i].handle, s->attr.connection_handle, tmpcharacteristics[i].instance_id, tmpcharacteristics[i].properties);
|
||||||
|
}
|
||||||
|
if (total_out) *total_out = tmp_total_out;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGattServiceGetCharacteristic(BtdevGattService *s, const BtdrvGattAttributeUuid *uuid, BtdevGattCharacteristic *characteristic, bool *flag) {
|
||||||
|
Result rc=0;
|
||||||
|
BtmGattCharacteristic tmpcharacteristics[100]={0};
|
||||||
|
u8 tmp_total_out=0;
|
||||||
|
bool tmp_flag=false;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = btmuGetGattCharacteristics(s->attr.connection_handle, s->attr.handle, tmpcharacteristics, 100, &tmp_total_out);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmp_total_out > 100) tmp_total_out = 100;
|
||||||
|
for (u8 i=0; i<tmp_total_out; i++) {
|
||||||
|
if (btdevGattAttributeUuidIsSame(&tmpcharacteristics[i].uuid, uuid)) {
|
||||||
|
btdevGattCharacteristicCreate(characteristic, &tmpcharacteristics[i].uuid, tmpcharacteristics[i].handle, s->attr.connection_handle, tmpcharacteristics[i].instance_id, tmpcharacteristics[i].properties);
|
||||||
|
tmp_flag=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flag) *flag = tmp_flag;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GattCharacteristic
|
||||||
|
|
||||||
|
void btdevGattCharacteristicCreate(BtdevGattCharacteristic *c, const BtdrvGattAttributeUuid *uuid, u16 handle, u32 connection_handle, u16 instance_id, u8 properties) {
|
||||||
|
memset(c, 0, sizeof(*c));
|
||||||
|
btdevGattAttributeCreate(&c->attr, uuid, handle, connection_handle);
|
||||||
|
c->attr.type = 0x1;
|
||||||
|
c->instance_id = instance_id;
|
||||||
|
c->properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGattCharacteristicGetService(BtdevGattCharacteristic *c, BtdevGattService *service) {
|
||||||
|
Result rc=0;
|
||||||
|
BtmGattService tmpservice={0};
|
||||||
|
bool flag=0;
|
||||||
|
|
||||||
|
rc = btmuGetBelongingGattService(c->attr.connection_handle, c->attr.handle, &tmpservice, &flag);
|
||||||
|
if (R_SUCCEEDED(rc) && !flag) rc = MAKERESULT(113, 512);
|
||||||
|
if (R_SUCCEEDED(rc)) btdevGattServiceCreate(service, &tmpservice.uuid, tmpservice.handle, c->attr.connection_handle, tmpservice.instance_id, tmpservice.end_group_handle, tmpservice.primary_service);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGattCharacteristicGetDescriptors(BtdevGattCharacteristic *c, BtdevGattDescriptor *descriptors, u8 count, u8 *total_out) {
|
||||||
|
Result rc=0;
|
||||||
|
u8 tmp_total_out=0;
|
||||||
|
BtmGattDescriptor tmpdescriptors[100]={0};
|
||||||
|
|
||||||
|
memset(descriptors, 0, sizeof(BtdevGattDescriptor)*count);
|
||||||
|
|
||||||
|
rc = btmuGetGattDescriptors(c->attr.connection_handle, c->attr.handle, tmpdescriptors, 100, &tmp_total_out);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmp_total_out > count) tmp_total_out = count;
|
||||||
|
for (u8 i=0; i<tmp_total_out; i++) {
|
||||||
|
btdevGattDescriptorCreate(&descriptors[i], &tmpdescriptors[i].uuid, tmpdescriptors[i].handle, c->attr.connection_handle);
|
||||||
|
}
|
||||||
|
if (total_out) *total_out = tmp_total_out;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGattCharacteristicGetDescriptor(BtdevGattCharacteristic *c, const BtdrvGattAttributeUuid *uuid, BtdevGattDescriptor *descriptor, bool *flag) {
|
||||||
|
Result rc=0;
|
||||||
|
u8 tmp_total_out=0;
|
||||||
|
bool tmp_flag=0;
|
||||||
|
BtmGattDescriptor tmpdescriptors[100]={0};
|
||||||
|
|
||||||
|
memset(descriptor, 0, sizeof(BtdevGattDescriptor));
|
||||||
|
|
||||||
|
rc = btmuGetGattDescriptors(c->attr.connection_handle, c->attr.handle, tmpdescriptors, 100, &tmp_total_out);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmp_total_out > 100) tmp_total_out = 100;
|
||||||
|
for (u8 i=0; i<tmp_total_out; i++) {
|
||||||
|
if (btdevGattAttributeUuidIsSame(&tmpdescriptors[i].uuid, uuid)) {
|
||||||
|
btdevGattDescriptorCreate(descriptor, &tmpdescriptors[i].uuid, tmpdescriptors[i].handle, c->attr.connection_handle);
|
||||||
|
tmp_flag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flag) *flag = tmp_flag;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void btdevGattCharacteristicSetValue(BtdevGattCharacteristic *c, const void* buffer, size_t size) {
|
||||||
|
if (buffer==NULL || size > sizeof(c->value)) return;
|
||||||
|
c->value_size = size;
|
||||||
|
memcpy(c->value, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 btdevGattCharacteristicGetValue(BtdevGattCharacteristic *c, void* buffer, size_t size) {
|
||||||
|
if (buffer==NULL) return 0;
|
||||||
|
u64 out_size = c->value_size;
|
||||||
|
if (size < out_size) out_size = size;
|
||||||
|
if (out_size > sizeof(c->value)) out_size = sizeof(c->value);
|
||||||
|
memcpy(buffer, c->value, out_size);
|
||||||
|
return out_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GattDescriptor
|
||||||
|
|
||||||
|
void btdevGattDescriptorCreate(BtdevGattDescriptor *d, const BtdrvGattAttributeUuid *uuid, u16 handle, u32 connection_handle) {
|
||||||
|
memset(d, 0, sizeof(*d));
|
||||||
|
btdevGattAttributeCreate(&d->attr, uuid, handle, connection_handle);
|
||||||
|
d->attr.type = 0x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGattDescriptorGetService(BtdevGattDescriptor *d, BtdevGattService *service) {
|
||||||
|
Result rc=0;
|
||||||
|
BtmGattService tmpservice={0};
|
||||||
|
bool flag=0;
|
||||||
|
|
||||||
|
rc = btmuGetBelongingGattService(d->attr.connection_handle, d->attr.handle, &tmpservice, &flag);
|
||||||
|
if (R_SUCCEEDED(rc) && !flag) rc = MAKERESULT(113, 512);
|
||||||
|
if (R_SUCCEEDED(rc)) btdevGattServiceCreate(service, &tmpservice.uuid, tmpservice.handle, d->attr.connection_handle, tmpservice.instance_id, tmpservice.end_group_handle, tmpservice.primary_service);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result btdevGattDescriptorGetCharacteristic(BtdevGattDescriptor *d, BtdevGattCharacteristic *characteristic) {
|
||||||
|
Result rc=0;
|
||||||
|
BtdevGattService tmpservice={0};
|
||||||
|
BtmGattCharacteristic tmpcharacteristics[100]={0};
|
||||||
|
u8 tmp_total_out=0;
|
||||||
|
|
||||||
|
rc = btdevGattDescriptorGetService(d, &tmpservice);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = btmuGetGattCharacteristics(d->attr.connection_handle, btdevGattAttributeGetHandle(&tmpservice.attr), tmpcharacteristics, 100, &tmp_total_out);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmp_total_out > 100) tmp_total_out = 100;
|
||||||
|
for (u8 i=0; i<tmp_total_out; i++) {
|
||||||
|
if (tmpcharacteristics[i].handle < d->attr.handle && (tmp_total_out-1 == i || d->attr.handle < tmpcharacteristics[i+1].handle)) {
|
||||||
|
btdevGattCharacteristicCreate(characteristic, &tmpcharacteristics[i].uuid, tmpcharacteristics[i].handle, d->attr.connection_handle, tmpcharacteristics[i].instance_id, tmpcharacteristics[i].properties);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (R_SUCCEEDED(rc)) rc = MAKERESULT(113, 512);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void btdevGattDescriptorSetValue(BtdevGattDescriptor *d, const void* buffer, size_t size) {
|
||||||
|
if (buffer==NULL || size > sizeof(d->value)) return;
|
||||||
|
d->value_size = size;
|
||||||
|
memcpy(d->value, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 btdevGattDescriptorGetValue(BtdevGattDescriptor *d, void* buffer, size_t size) {
|
||||||
|
if (buffer==NULL) return 0;
|
||||||
|
u64 out_size = d->value_size;
|
||||||
|
if (size < out_size) out_size = size;
|
||||||
|
if (out_size > sizeof(d->value)) out_size = sizeof(d->value);
|
||||||
|
memcpy(buffer, d->value, out_size);
|
||||||
|
return out_size;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user