From 3f24c35c24f3d0e58caf6e2d11939a05a968c1ab Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 10 Jan 2023 15:42:14 -0600 Subject: [PATCH] WIP: add ble connect timeout TODO: - https://crbug.com/1406311 needs to be fixed - timeout needs to be added to bootloader connect as well Issue: https://github.com/pybricks/support/issues/911 --- src/ble/alerts/FailedToConnect.tsx | 24 ++++++++++++++++++ src/ble/alerts/index.ts | 4 ++- src/ble/alerts/translations/en.json | 4 +++ src/ble/sagas.ts | 39 +++++++++++++++++++++++++++-- 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/ble/alerts/FailedToConnect.tsx diff --git a/src/ble/alerts/FailedToConnect.tsx b/src/ble/alerts/FailedToConnect.tsx new file mode 100644 index 000000000..5e56aa0a0 --- /dev/null +++ b/src/ble/alerts/FailedToConnect.tsx @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2023 The Pybricks Authors + +import { Intent } from '@blueprintjs/core'; +import React from 'react'; +import type { CreateToast } from '../../toasterTypes'; +import { useI18n } from './i18n'; + +const FailedToConnect: React.VoidFunctionComponent = () => { + const i18n = useI18n(); + return ( + <> +

{i18n.translate('failedToConnect.message')}

+

{i18n.translate('failedToConnect.suggestion')}

+ + ); +}; + +export const failedToConnect: CreateToast = (onAction) => ({ + message: , + icon: 'error', + intent: Intent.DANGER, + onDismiss: () => onAction('dismiss'), +}); diff --git a/src/ble/alerts/index.ts b/src/ble/alerts/index.ts index 22b7ffc04..7bd17973d 100644 --- a/src/ble/alerts/index.ts +++ b/src/ble/alerts/index.ts @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2022 The Pybricks Authors +// Copyright (c) 2022-2023 The Pybricks Authors import { bluetoothNotAvailable } from './BluetoothNotAvailable'; +import { failedToConnect } from './FailedToConnect'; import { missingService } from './MissingService'; import { noGatt } from './NoGatt'; import { noHub } from './NoHub'; @@ -11,6 +12,7 @@ import { oldFirmware } from './OldFirmware'; // gathers all of the alert creation functions for passing up to the top level export default { bluetoothNotAvailable, + failedToConnect, missingService, noGatt, noHub, diff --git a/src/ble/alerts/translations/en.json b/src/ble/alerts/translations/en.json index 97c4da8bc..7efe8d07a 100644 --- a/src/ble/alerts/translations/en.json +++ b/src/ble/alerts/translations/en.json @@ -13,6 +13,10 @@ "noGatt": { "message": "The web browser did not give permission to use Bluetooth Low Energy." }, + "failedToConnect": { + "message": "Failed to connect.", + "suggestion": "Is the hub still turned on with no programs running?" + }, "missingService": { "message": "Connected to hub but failed to get {serviceName} service.", "suggestion1": "Ensure that you are using the most recent firmware.", diff --git a/src/ble/sagas.ts b/src/ble/sagas.ts index e5aa87e82..e6d881f7a 100644 --- a/src/ble/sagas.ts +++ b/src/ble/sagas.ts @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2020-2022 The Pybricks Authors +// Copyright (c) 2020-2023 The Pybricks Authors // // Manages connection to a Bluetooth Low Energy device running Pybricks firmware. @@ -146,6 +146,9 @@ function* handleBleConnectPybricks(): Generator { }), ); + // TODO: remove debug print + console.log('device', device); + if (!device) { yield* put(alertsShowAlert('ble', 'noHub')); yield* put(bleDidFailToConnectPybricks()); @@ -181,7 +184,39 @@ function* handleBleConnectPybricks(): Generator { defer.push(() => disconnectChannel.close()); - const server = yield* call(() => gatt.connect()); + const timeout = setTimeout(() => { + // TODO: remove debug print + console.log('calling disconnect'); + gatt.disconnect(); + }, 10000); + + const server = yield* call(() => + gatt.connect().catch((err) => { + // TODO: remove debug print + console.error(err); + + // timeout or other connection problem + if (err instanceof DOMException && err.name === 'AbortError') { + return undefined; + } + + throw err; + }), + ); + + clearTimeout(timeout); + + // TODO: remove debug print + console.log(server); + + if (!server) { + yield* put(alertsShowAlert('ble', 'failedToConnect')); + yield* put(bleDidFailToConnectPybricks()); + return; + } + + // TODO: remove debug print + console.log('server', server); defer.push(() => server.disconnect());