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:
Rohit Sangwan
2024-02-17 00:06:36 +05:30
committed by GitHub
parent 35d4737f3a
commit 663bc76dfe
5 changed files with 129 additions and 59 deletions
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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;
}
}
}
+76 -44
View File
@@ -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;
+3
View File
@@ -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;