#include <simpleble/Peripheral.h>
#import "AdapterBaseMacOS.h"
#import "AdapterMac.h"
#import "BuilderBase.h"
#import "CommonUtils.h"
#import "PeripheralMac.h"
#include <fmt/core.h>
#include <chrono>
#include <limits>
#include <memory>
#include <thread>
using namespace SimpleBLE;
AdapterMac::AdapterMac() {
opaque_internal_ = (__bridge_retained void*)[[AdapterBaseMacOS alloc] init:this];
}
AdapterMac::~AdapterMac() {
AdapterBaseMacOS* internal = (__bridge_transfer AdapterBaseMacOS*)opaque_internal_;
internal = nil;
}
bool AdapterMac::bluetooth_enabled() {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
return [internal isBluetoothEnabled];
}
void* AdapterMac::underlying() const {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
return [internal underlying];
}
std::string AdapterMac::identifier() { return fmt::format("Default Adapter [{}]", this->address()); }
BluetoothAddress AdapterMac::address() const {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
return [[internal address] UTF8String];
}
void AdapterMac::power_on() {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
[internal powerOn];
}
void AdapterMac::power_off() {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
[internal powerOff];
}
bool AdapterMac::is_powered() {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
return [internal isPowered];
}
BluetoothAddress AdapterMac::address() { return const_cast<const AdapterMac*>(this)->address(); }
void AdapterMac::scan_start() {
{
std::scoped_lock lock(peripherals_mutex_);
this->seen_peripherals_.clear();
}
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
[internal scanStart];
SAFE_CALLBACK_CALL(this->_callback_on_scan_start);
}
void AdapterMac::scan_stop() {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
[internal scanStop];
SAFE_CALLBACK_CALL(this->_callback_on_scan_stop);
}
void AdapterMac::scan_for(int timeout_ms) {
this->scan_start();
std::this_thread::sleep_for(std::chrono::milliseconds(timeout_ms));
this->scan_stop();
}
bool AdapterMac::scan_is_active() {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
return [internal scanIsActive];
}
SharedPtrVector<PeripheralBase> AdapterMac::scan_get_results() {
std::scoped_lock lock(peripherals_mutex_);
SharedPtrVector<PeripheralBase> peripherals = Util::values(seen_peripherals_);
return peripherals;
}
SharedPtrVector<PeripheralBase> AdapterMac::get_paired_peripherals() { return {}; }
SharedPtrVector<PeripheralBase> AdapterMac::retrieve_cached_peripherals(const std::vector<BluetoothAddress>& identifiers) {
AdapterBaseMacOS* internal = (__bridge AdapterBaseMacOS*)opaque_internal_;
advertising_data_t advertising_data{};
advertising_data.connectable = true;
advertising_data.rssi = std::numeric_limits<int16_t>::min();
advertising_data.tx_power = std::numeric_limits<int16_t>::min();
void* opaque_adapter = [internal underlying];
NSArray<CBPeripheral*>* retrieved = [internal retrieveCachedPeripherals:identifiers];
SharedPtrVector<PeripheralBase> peripherals;
peripherals.reserve(retrieved.count);
for (CBPeripheral* cb_peripheral in retrieved) {
peripherals.push_back(get_or_create_peripheral((__bridge void*)cb_peripheral, opaque_adapter, advertising_data));
}
return peripherals;
}
void AdapterMac::delegate_did_discover_peripheral(void* opaque_peripheral, void* opaque_adapter, advertising_data_t advertising_data) {
bool is_new_peripheral = false;
auto base_peripheral = get_or_create_peripheral(opaque_peripheral, opaque_adapter, advertising_data);
base_peripheral->update_advertising_data(advertising_data);
Peripheral peripheral = Factory::build(base_peripheral);
{
std::scoped_lock lock(peripherals_mutex_);
is_new_peripheral = this->seen_peripherals_.count(opaque_peripheral) == 0;
if (is_new_peripheral) {
this->seen_peripherals_.insert(std::make_pair(opaque_peripheral, base_peripheral));
}
}
if (is_new_peripheral) {
SAFE_CALLBACK_CALL(this->_callback_on_scan_found, peripheral);
} else {
SAFE_CALLBACK_CALL(this->_callback_on_scan_updated, peripheral);
}
}
std::shared_ptr<PeripheralMac> AdapterMac::get_or_create_peripheral(void* opaque_peripheral, void* opaque_adapter,
advertising_data_t advertising_data) {
std::scoped_lock lock(peripherals_mutex_);
auto& peripheral = peripherals_[opaque_peripheral];
if (!peripheral) {
peripheral = std::make_shared<PeripheralMac>(opaque_peripheral, opaque_adapter, advertising_data);
}
return peripheral;
}
void AdapterMac::delegate_did_connect_peripheral(void* opaque_peripheral) {
std::shared_ptr<PeripheralMac> base_peripheral;
{
std::scoped_lock lock(peripherals_mutex_);
if (this->peripherals_.count(opaque_peripheral) == 0) {
throw Exception::InvalidReference();
}
base_peripheral = this->peripherals_.at(opaque_peripheral);
}
base_peripheral->delegate_did_connect();
}
void AdapterMac::delegate_did_fail_to_connect_peripheral(void* opaque_peripheral, void* opaque_error) {
std::shared_ptr<PeripheralMac> base_peripheral;
{
std::scoped_lock lock(peripherals_mutex_);
if (this->peripherals_.count(opaque_peripheral) == 0) {
throw Exception::InvalidReference();
}
base_peripheral = this->peripherals_.at(opaque_peripheral);
}
base_peripheral->delegate_did_fail_to_connect(opaque_error);
}
void AdapterMac::delegate_did_disconnect_peripheral(void* opaque_peripheral, void* opaque_error) {
std::shared_ptr<PeripheralMac> base_peripheral;
{
std::scoped_lock lock(peripherals_mutex_);
if (this->peripherals_.count(opaque_peripheral) == 0) {
throw Exception::InvalidReference();
}
base_peripheral = this->peripherals_.at(opaque_peripheral);
}
base_peripheral->delegate_did_disconnect(opaque_error);
}
void AdapterMac::delegate_did_power_on() { SAFE_CALLBACK_CALL(this->_callback_on_power_on); }
void AdapterMac::delegate_did_power_off() { SAFE_CALLBACK_CALL(this->_callback_on_power_off); }