Improve Windows and Linux error handling (#12)
* Improve windows and linux error handeling * Send proper error code from windows for write command * Fix Linux * Fix getConnectedDevices on windows --------- Co-authored-by: fotidim <fdimanidis@gmail.com> Co-authored-by: fotidim <foti@navideck.com>
This commit is contained in:
@@ -62,7 +62,7 @@ class _MyAppState extends State<MyApp> {
|
||||
};
|
||||
|
||||
UniversalBle.onScanResult = (result) {
|
||||
debugPrint("${result.name} ${result.manufacturerData}");
|
||||
// debugPrint("${result.name} ${result.manufacturerData}");
|
||||
int index = _scanResults.indexWhere((e) => e.deviceId == result.deviceId);
|
||||
if (index == -1) {
|
||||
_scanResults.add(result);
|
||||
|
||||
@@ -386,7 +386,7 @@ packages:
|
||||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.9.1"
|
||||
version: "0.9.2"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:typed_data';
|
||||
|
||||
import 'package:bluez/bluez.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:universal_ble/src/models/model_exports.dart';
|
||||
import 'package:universal_ble/src/universal_ble_platform_interface.dart';
|
||||
|
||||
@@ -179,9 +180,16 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
@override
|
||||
Future<Uint8List> readValue(
|
||||
String deviceId, String service, String characteristic) async {
|
||||
var c = _getCharacteristic(deviceId, service, characteristic);
|
||||
var data = await c.readValue();
|
||||
return Uint8List.fromList(data);
|
||||
try {
|
||||
var c = _getCharacteristic(deviceId, service, characteristic);
|
||||
var data = await c.readValue();
|
||||
return Uint8List.fromList(data);
|
||||
} on BlueZFailedException catch (e) {
|
||||
throw PlatformException(
|
||||
code: e.errorCode ?? "ReadFailed",
|
||||
message: e.message,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -191,16 +199,23 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
String characteristic,
|
||||
Uint8List value,
|
||||
BleOutputProperty bleOutputProperty) async {
|
||||
var c = _getCharacteristic(deviceId, service, characteristic);
|
||||
if (bleOutputProperty == BleOutputProperty.withResponse) {
|
||||
await c.writeValue(
|
||||
value,
|
||||
type: BlueZGattCharacteristicWriteType.request,
|
||||
);
|
||||
} else {
|
||||
await c.writeValue(
|
||||
value,
|
||||
type: BlueZGattCharacteristicWriteType.command,
|
||||
try {
|
||||
var c = _getCharacteristic(deviceId, service, characteristic);
|
||||
if (bleOutputProperty == BleOutputProperty.withResponse) {
|
||||
await c.writeValue(
|
||||
value,
|
||||
type: BlueZGattCharacteristicWriteType.request,
|
||||
);
|
||||
} else {
|
||||
await c.writeValue(
|
||||
value,
|
||||
type: BlueZGattCharacteristicWriteType.command,
|
||||
);
|
||||
}
|
||||
} on BlueZFailedException catch (e) {
|
||||
throw PlatformException(
|
||||
code: e.errorCode ?? "WriteFailed",
|
||||
message: e.message,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -486,3 +501,23 @@ extension on BlueZGattCharacteristicFlag {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
extension on BlueZFailedException {
|
||||
/// Extract error code from message and parse into decimal
|
||||
/// example: 'Operation failed with ATT error: 0x90' => 144
|
||||
String? get errorCode {
|
||||
try {
|
||||
RegExp regExp = RegExp(r'0x\w+');
|
||||
Match? match = regExp.firstMatch(message);
|
||||
String? code = match?.group(0);
|
||||
if (code == null) return null;
|
||||
int? decimalValue = int.tryParse(
|
||||
code.replaceFirst('0x', ''),
|
||||
radix: 16,
|
||||
);
|
||||
return decimalValue?.toString() ?? code;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,28 +322,8 @@ namespace universal_ble
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto async_c = gatt_characteristic_holder.obj.WriteValueAsync(from_bytevc(value), writeOption);
|
||||
async_c.Completed([&, result](IAsyncOperation<GattCommunicationStatus> const &sender, AsyncStatus const args)
|
||||
{
|
||||
auto writeResult = sender.GetResults();
|
||||
switch (writeResult)
|
||||
{
|
||||
case GenericAttributeProfile::GattCommunicationStatus::Success:
|
||||
result(std::nullopt);
|
||||
return;
|
||||
case GenericAttributeProfile::GattCommunicationStatus::Unreachable:
|
||||
result(FlutterError("Unreachable", "Failed to write value"));
|
||||
return;
|
||||
case GenericAttributeProfile::GattCommunicationStatus::ProtocolError:
|
||||
result(FlutterError("ProtocolError", "Failed to write value"));
|
||||
return;
|
||||
case GenericAttributeProfile::GattCommunicationStatus::AccessDenied:
|
||||
result(FlutterError("AccessDenied", "Failed to write value"));
|
||||
return;
|
||||
default:
|
||||
result(FlutterError("Failed", "Failed to write value"));
|
||||
return;
|
||||
} });
|
||||
|
||||
WriteAsync(gatt_characteristic_holder.obj, writeOption, value, result);
|
||||
}
|
||||
catch (const FlutterError &err)
|
||||
{
|
||||
@@ -774,6 +754,47 @@ namespace universal_ble
|
||||
}
|
||||
}
|
||||
|
||||
winrt::fire_and_forget UniversalBlePlugin::WriteAsync(GattCharacteristic characteristic, GattWriteOption writeOption,
|
||||
const std::vector<uint8_t> &value, std::function<void(std::optional<FlutterError> reply)> result)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto writeResult = co_await characteristic.WriteValueAsync(from_bytevc(value), writeOption);
|
||||
switch (writeResult)
|
||||
{
|
||||
case GenericAttributeProfile::GattCommunicationStatus::Success:
|
||||
result(std::nullopt);
|
||||
co_return;
|
||||
case GenericAttributeProfile::GattCommunicationStatus::Unreachable:
|
||||
result(FlutterError("Unreachable", "Failed to write value"));
|
||||
co_return;
|
||||
case GenericAttributeProfile::GattCommunicationStatus::ProtocolError:
|
||||
result(FlutterError("ProtocolError", "Failed to write value"));
|
||||
co_return;
|
||||
case GenericAttributeProfile::GattCommunicationStatus::AccessDenied:
|
||||
result(FlutterError("AccessDenied", "Failed to write value"));
|
||||
co_return;
|
||||
default:
|
||||
result(FlutterError("Failed", "Failed to write value"));
|
||||
co_return;
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error &err)
|
||||
{
|
||||
int errorCode = err.code();
|
||||
std::cout << "WriteValueLog: " << winrt::to_string(err.message()) << " ErrorCode: " << std::to_string(errorCode) << std::endl;
|
||||
result(FlutterError(std::to_string(errorCode), winrt::to_string(err.message())));
|
||||
}
|
||||
catch (const std::exception &err)
|
||||
{
|
||||
result(FlutterError("WriteFailed", err.what()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result(FlutterError("WriteFailed", "Unknown error"));
|
||||
}
|
||||
}
|
||||
|
||||
winrt::fire_and_forget UniversalBlePlugin::ConnectAsync(uint64_t bluetoothAddress)
|
||||
{
|
||||
BluetoothLEDevice device = co_await BluetoothLEDevice::FromBluetoothAddressAsync(bluetoothAddress);
|
||||
@@ -883,37 +904,48 @@ namespace universal_ble
|
||||
flutter::EncodableList results = flutter::EncodableList();
|
||||
for (auto &&deviceInfo : devices)
|
||||
{
|
||||
BluetoothLEDevice device = co_await BluetoothLEDevice::FromIdAsync(deviceInfo.Id());
|
||||
auto deviceId = _mac_address_to_str(device.BluetoothAddress());
|
||||
// Filter by services
|
||||
if (!with_services.empty())
|
||||
{
|
||||
auto serviceResult = co_await device.GetGattServicesAsync(BluetoothCacheMode::Cached);
|
||||
if (serviceResult.Status() == GattCommunicationStatus::Success)
|
||||
try{
|
||||
BluetoothLEDevice device = co_await BluetoothLEDevice::FromIdAsync(deviceInfo.Id());
|
||||
auto deviceId = _mac_address_to_str(device.BluetoothAddress());
|
||||
// Filter by services
|
||||
if (!with_services.empty())
|
||||
{
|
||||
bool hasService = false;
|
||||
for (auto service : serviceResult.Services())
|
||||
auto serviceResult = co_await device.GetGattServicesAsync(BluetoothCacheMode::Cached);
|
||||
if (serviceResult.Status() == GattCommunicationStatus::Success)
|
||||
{
|
||||
std::string serviceUUID = to_uuidstr(service.Uuid());
|
||||
if (std::find(with_services.begin(), with_services.end(), serviceUUID) != with_services.end())
|
||||
bool hasService = false;
|
||||
for (auto service : serviceResult.Services())
|
||||
{
|
||||
hasService = true;
|
||||
break;
|
||||
std::string serviceUUID = to_uuidstr(service.Uuid());
|
||||
if (std::find(with_services.begin(), with_services.end(), serviceUUID) != with_services.end())
|
||||
{
|
||||
hasService = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasService)
|
||||
continue;
|
||||
}
|
||||
if (!hasService)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Add to results, if pass all filters
|
||||
auto universalScanResult = UniversalBleScanResult(deviceId);
|
||||
universalScanResult.set_name(winrt::to_string(deviceInfo.Name()));
|
||||
universalScanResult.set_is_paired(deviceInfo.Pairing().IsPaired());
|
||||
results.push_back(flutter::CustomEncodableValue(universalScanResult));
|
||||
// deviceConnectableStatus[_str_to_mac_address(deviceId)] = true;
|
||||
// Add to results, if pass all filters
|
||||
auto universalScanResult = UniversalBleScanResult(deviceId);
|
||||
universalScanResult.set_name(winrt::to_string(deviceInfo.Name()));
|
||||
universalScanResult.set_is_paired(deviceInfo.Pairing().IsPaired());
|
||||
results.push_back(flutter::CustomEncodableValue(universalScanResult));
|
||||
}catch(...){ }
|
||||
}
|
||||
result(results);
|
||||
}
|
||||
catch (const winrt::hresult_error &err)
|
||||
{
|
||||
int errorCode = err.code();
|
||||
std::cout << "GetConnectedDeviceLog: " << winrt::to_string(err.message()) << " ErrorCode: " << std::to_string(errorCode) << std::endl;
|
||||
result(FlutterError(std::to_string(errorCode), winrt::to_string(err.message())));
|
||||
}
|
||||
catch (const std::exception &err)
|
||||
{
|
||||
result(FlutterError(err.what()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "Unknown error GetConnectedDevicesAsync" << std::endl;
|
||||
|
||||
@@ -120,6 +120,9 @@ namespace universal_ble
|
||||
winrt::fire_and_forget GetConnectedDevicesAsync(std::vector<std::string> with_services,
|
||||
std::function<void(ErrorOr<flutter::EncodableList> reply)> result);
|
||||
winrt::fire_and_forget IsPairedAsync(std::string device_id, std::function<void(ErrorOr<bool> reply)> result);
|
||||
winrt::fire_and_forget WriteAsync(GattCharacteristic characteristic, GattWriteOption writeOption,
|
||||
const std::vector<uint8_t> &value,
|
||||
std::function<void(std::optional<FlutterError> reply)> result);
|
||||
|
||||
// UniversalBlePlatformChannel implementation.
|
||||
void GetBluetoothAvailabilityState(std::function<void(ErrorOr<int64_t> reply)> result) override;
|
||||
|
||||
Reference in New Issue
Block a user