@microbit/microbit-connection 0.1.0 → 0.9.0-apps.alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/build/cjs/accelerometer-service.d.ts +5 -5
- package/build/cjs/accelerometer-service.js +41 -42
- package/build/cjs/accelerometer-service.js.map +1 -1
- package/build/cjs/async-util.d.ts +9 -0
- package/build/cjs/async-util.js +27 -7
- package/build/cjs/async-util.js.map +1 -1
- package/build/cjs/bluetooth-device-wrapper.d.ts +61 -27
- package/build/cjs/bluetooth-device-wrapper.js +285 -266
- package/build/cjs/bluetooth-device-wrapper.js.map +1 -1
- package/build/cjs/bluetooth-profile.d.ts +43 -35
- package/build/cjs/bluetooth-profile.js +35 -29
- package/build/cjs/bluetooth-profile.js.map +1 -1
- package/build/cjs/bluetooth.d.ts +10 -6
- package/build/cjs/bluetooth.js +286 -100
- package/build/cjs/bluetooth.js.map +1 -1
- package/build/cjs/button-service.d.ts +5 -5
- package/build/cjs/button-service.js +31 -45
- package/build/cjs/button-service.js.map +1 -1
- package/build/cjs/device-information-service.d.ts +6 -0
- package/build/cjs/device-information-service.js +34 -0
- package/build/cjs/device-information-service.js.map +1 -0
- package/build/cjs/device.d.ts +65 -8
- package/build/cjs/device.js +16 -2
- package/build/cjs/device.js.map +1 -1
- package/build/cjs/dfu-service.d.ts +9 -0
- package/build/cjs/dfu-service.js +26 -0
- package/build/cjs/dfu-service.js.map +1 -0
- package/build/cjs/flashing/flashing-full.d.ts +14 -0
- package/build/cjs/flashing/flashing-full.js +87 -0
- package/build/cjs/flashing/flashing-full.js.map +1 -0
- package/build/cjs/flashing/flashing-makecode.d.ts +6 -0
- package/build/cjs/flashing/flashing-makecode.js +48 -0
- package/build/cjs/flashing/flashing-makecode.js.map +1 -0
- package/build/cjs/flashing/flashing-partial.d.ts +9 -0
- package/build/cjs/flashing/flashing-partial.js +98 -0
- package/build/cjs/flashing/flashing-partial.js.map +1 -0
- package/build/cjs/flashing/flashing-v1.d.ts +11 -0
- package/build/cjs/flashing/flashing-v1.js +24 -0
- package/build/cjs/flashing/flashing-v1.js.map +1 -0
- package/build/cjs/flashing/nordic-dfu.d.ts +3 -0
- package/build/cjs/flashing/nordic-dfu.js +214 -0
- package/build/cjs/flashing/nordic-dfu.js.map +1 -0
- package/build/cjs/flashing/zip.d.ts +12 -0
- package/build/cjs/flashing/zip.js +177 -0
- package/build/cjs/flashing/zip.js.map +1 -0
- package/build/cjs/index.d.ts +3 -3
- package/build/cjs/index.js +2 -1
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/led-service.d.ts +5 -7
- package/build/cjs/led-service.js +13 -44
- package/build/cjs/led-service.js.map +1 -1
- package/build/cjs/logging.d.ts +1 -1
- package/build/cjs/logging.js +3 -3
- package/build/cjs/logging.js.map +1 -1
- package/build/cjs/magnetometer-service.d.ts +5 -9
- package/build/cjs/magnetometer-service.js +30 -65
- package/build/cjs/magnetometer-service.js.map +1 -1
- package/build/cjs/partial-flashing-service.d.ts +45 -0
- package/build/cjs/partial-flashing-service.js +110 -0
- package/build/cjs/partial-flashing-service.js.map +1 -0
- package/build/cjs/uart-service.d.ts +4 -5
- package/build/cjs/uart-service.js +19 -40
- package/build/cjs/uart-service.js.map +1 -1
- package/build/cjs/usb-device-wrapper.js +33 -8
- package/build/cjs/usb-device-wrapper.js.map +1 -1
- package/build/cjs/usb-partial-flashing.d.ts +1 -3
- package/build/cjs/usb-partial-flashing.js +4 -3
- package/build/cjs/usb-partial-flashing.js.map +1 -1
- package/build/cjs/usb-radio-bridge.js +1 -2
- package/build/cjs/usb-radio-bridge.js.map +1 -1
- package/build/cjs/usb.d.ts +4 -2
- package/build/cjs/usb.js +31 -16
- package/build/cjs/usb.js.map +1 -1
- package/build/esm/accelerometer-service.d.ts +5 -5
- package/build/esm/accelerometer-service.js +42 -43
- package/build/esm/accelerometer-service.js.map +1 -1
- package/build/esm/async-util.d.ts +9 -0
- package/build/esm/async-util.js +22 -6
- package/build/esm/async-util.js.map +1 -1
- package/build/esm/bluetooth-device-wrapper.d.ts +61 -27
- package/build/esm/bluetooth-device-wrapper.js +284 -265
- package/build/esm/bluetooth-device-wrapper.js.map +1 -1
- package/build/esm/bluetooth-profile.d.ts +43 -35
- package/build/esm/bluetooth-profile.js +35 -29
- package/build/esm/bluetooth-profile.js.map +1 -1
- package/build/esm/bluetooth.d.ts +10 -6
- package/build/esm/bluetooth.js +263 -103
- package/build/esm/bluetooth.js.map +1 -1
- package/build/esm/button-service.d.ts +5 -5
- package/build/esm/button-service.js +32 -46
- package/build/esm/button-service.js.map +1 -1
- package/build/esm/device-information-service.d.ts +6 -0
- package/build/esm/device-information-service.js +30 -0
- package/build/esm/device-information-service.js.map +1 -0
- package/build/esm/device.d.ts +65 -8
- package/build/esm/device.js +15 -1
- package/build/esm/device.js.map +1 -1
- package/build/esm/dfu-service.d.ts +9 -0
- package/build/esm/dfu-service.js +22 -0
- package/build/esm/dfu-service.js.map +1 -0
- package/build/esm/flashing/flashing-full.d.ts +14 -0
- package/build/esm/flashing/flashing-full.js +84 -0
- package/build/esm/flashing/flashing-full.js.map +1 -0
- package/build/esm/flashing/flashing-makecode.d.ts +6 -0
- package/build/esm/flashing/flashing-makecode.js +44 -0
- package/build/esm/flashing/flashing-makecode.js.map +1 -0
- package/build/esm/flashing/flashing-partial.d.ts +9 -0
- package/build/esm/flashing/flashing-partial.js +95 -0
- package/build/esm/flashing/flashing-partial.js.map +1 -0
- package/build/esm/flashing/flashing-v1.d.ts +11 -0
- package/build/esm/flashing/flashing-v1.js +20 -0
- package/build/esm/flashing/flashing-v1.js.map +1 -0
- package/build/esm/flashing/nordic-dfu.d.ts +3 -0
- package/build/esm/flashing/nordic-dfu.js +211 -0
- package/build/esm/flashing/nordic-dfu.js.map +1 -0
- package/build/esm/flashing/zip.d.ts +12 -0
- package/build/esm/flashing/zip.js +174 -0
- package/build/esm/flashing/zip.js.map +1 -0
- package/build/esm/index.d.ts +3 -3
- package/build/esm/index.js +2 -2
- package/build/esm/index.js.map +1 -1
- package/build/esm/led-service.d.ts +5 -7
- package/build/esm/led-service.js +13 -44
- package/build/esm/led-service.js.map +1 -1
- package/build/esm/logging.d.ts +1 -1
- package/build/esm/logging.js +1 -1
- package/build/esm/logging.js.map +1 -1
- package/build/esm/magnetometer-service.d.ts +5 -9
- package/build/esm/magnetometer-service.js +31 -66
- package/build/esm/magnetometer-service.js.map +1 -1
- package/build/esm/partial-flashing-service.d.ts +45 -0
- package/build/esm/partial-flashing-service.js +106 -0
- package/build/esm/partial-flashing-service.js.map +1 -0
- package/build/esm/uart-service.d.ts +4 -5
- package/build/esm/uart-service.js +19 -40
- package/build/esm/uart-service.js.map +1 -1
- package/build/esm/usb-device-wrapper.js +33 -8
- package/build/esm/usb-device-wrapper.js.map +1 -1
- package/build/esm/usb-partial-flashing.d.ts +1 -3
- package/build/esm/usb-partial-flashing.js +4 -3
- package/build/esm/usb-partial-flashing.js.map +1 -1
- package/build/esm/usb-radio-bridge.js +2 -3
- package/build/esm/usb-radio-bridge.js.map +1 -1
- package/build/esm/usb.d.ts +4 -2
- package/build/esm/usb.js +33 -18
- package/build/esm/usb.js.map +1 -1
- package/package.json +5 -1
|
@@ -5,68 +5,47 @@
|
|
|
5
5
|
* SPDX-License-Identifier: MIT
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
8
|
+
exports.BluetoothDeviceWrapper = exports.isAndroid = exports.scanningTimeoutInMs = exports.connectTimeoutInMs = exports.bondingTimeoutInMs = void 0;
|
|
9
|
+
const bluetooth_le_1 = require("@capacitor-community/bluetooth-le");
|
|
10
|
+
const core_1 = require("@capacitor/core");
|
|
9
11
|
const accelerometer_service_js_1 = require("./accelerometer-service.js");
|
|
10
|
-
const
|
|
12
|
+
const async_util_js_1 = require("./async-util.js");
|
|
11
13
|
const button_service_js_1 = require("./button-service.js");
|
|
14
|
+
const device_information_service_js_1 = require("./device-information-service.js");
|
|
12
15
|
const device_js_1 = require("./device.js");
|
|
13
16
|
const led_service_js_1 = require("./led-service.js");
|
|
14
17
|
const logging_js_1 = require("./logging.js");
|
|
15
18
|
const magnetometer_service_js_1 = require("./magnetometer-service.js");
|
|
16
|
-
const
|
|
19
|
+
const partial_flashing_service_js_1 = require("./partial-flashing-service.js");
|
|
17
20
|
const uart_service_js_1 = require("./uart-service.js");
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
configurable: true,
|
|
45
|
-
writable: true,
|
|
46
|
-
value: events
|
|
47
|
-
});
|
|
48
|
-
Object.defineProperty(this, "service", {
|
|
49
|
-
enumerable: true,
|
|
50
|
-
configurable: true,
|
|
51
|
-
writable: true,
|
|
52
|
-
value: void 0
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
get() {
|
|
56
|
-
return this.service;
|
|
57
|
-
}
|
|
58
|
-
async createIfNeeded(gattServer, dispatcher, queueGattOperation, listenerInit) {
|
|
59
|
-
this.service =
|
|
60
|
-
this.service ??
|
|
61
|
-
(await this.serviceFactory(gattServer, dispatcher, queueGattOperation, listenerInit));
|
|
62
|
-
return this.service;
|
|
63
|
-
}
|
|
64
|
-
dispose() {
|
|
65
|
-
this.service = undefined;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
21
|
+
exports.bondingTimeoutInMs = 40_000;
|
|
22
|
+
exports.connectTimeoutInMs = 10_000;
|
|
23
|
+
exports.scanningTimeoutInMs = 10_000;
|
|
24
|
+
const isAndroid = () => core_1.Capacitor.getPlatform() === "android";
|
|
25
|
+
exports.isAndroid = isAndroid;
|
|
26
|
+
// TODO: We've removed the support for these behaviours as we need to
|
|
27
|
+
// re-evaluate how best to support then via capacitor-ble (or reinstate
|
|
28
|
+
// the direct Web Bluetooth connection code.
|
|
29
|
+
//
|
|
30
|
+
// On ChromeOS and Mac there's no timeout and no clear way to abort
|
|
31
|
+
// device.gatt.connect(), so we accept that sometimes we'll still
|
|
32
|
+
// be trying to connect when we'd rather not be. If it succeeds when
|
|
33
|
+
// we no longer intend to be connected then we disconnect at that
|
|
34
|
+
// point. If we try to connect when a previous connection attempt is
|
|
35
|
+
// still around then we wait for it for our timeout period.
|
|
36
|
+
//
|
|
37
|
+
// On Windows it times out after 7s.
|
|
38
|
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=684073
|
|
39
|
+
//
|
|
40
|
+
// Additionally we've remove the delay before trying to connect again
|
|
41
|
+
// on Windows.
|
|
42
|
+
//
|
|
43
|
+
// We also used to have a timeout around requestDevice that reloaded the page.
|
|
44
|
+
//
|
|
45
|
+
// > In some situations the Chrome device prompt simply doesn't appear so we time
|
|
46
|
+
// > this out after 30 seconds and reload the page
|
|
68
47
|
class BluetoothDeviceWrapper {
|
|
69
|
-
constructor(device, logging = new logging_js_1.
|
|
48
|
+
constructor(device, logging = new logging_js_1.ConsoleLogging(), dispatchTypedEvent, currentEvents, callbacks) {
|
|
70
49
|
Object.defineProperty(this, "device", {
|
|
71
50
|
enumerable: true,
|
|
72
51
|
configurable: true,
|
|
@@ -79,12 +58,6 @@ class BluetoothDeviceWrapper {
|
|
|
79
58
|
writable: true,
|
|
80
59
|
value: logging
|
|
81
60
|
});
|
|
82
|
-
Object.defineProperty(this, "dispatchTypedEvent", {
|
|
83
|
-
enumerable: true,
|
|
84
|
-
configurable: true,
|
|
85
|
-
writable: true,
|
|
86
|
-
value: dispatchTypedEvent
|
|
87
|
-
});
|
|
88
61
|
Object.defineProperty(this, "currentEvents", {
|
|
89
62
|
enumerable: true,
|
|
90
63
|
configurable: true,
|
|
@@ -105,138 +78,103 @@ class BluetoothDeviceWrapper {
|
|
|
105
78
|
writable: true,
|
|
106
79
|
value: 0
|
|
107
80
|
});
|
|
108
|
-
|
|
109
|
-
// device.gatt.connect(), so we accept that sometimes we'll still
|
|
110
|
-
// be trying to connect when we'd rather not be. If it succeeds when
|
|
111
|
-
// we no longer intend to be connected then we disconnect at that
|
|
112
|
-
// point. If we try to connect when a previous connection attempt is
|
|
113
|
-
// still around then we wait for it for our timeout period.
|
|
114
|
-
//
|
|
115
|
-
// On Windows it times out after 7s.
|
|
116
|
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=684073
|
|
117
|
-
Object.defineProperty(this, "gattConnectPromise", {
|
|
81
|
+
Object.defineProperty(this, "connected", {
|
|
118
82
|
enumerable: true,
|
|
119
83
|
configurable: true,
|
|
120
84
|
writable: true,
|
|
121
|
-
value:
|
|
122
|
-
});
|
|
123
|
-
Object.defineProperty(this, "disconnectPromise", {
|
|
124
|
-
enumerable: true,
|
|
125
|
-
configurable: true,
|
|
126
|
-
writable: true,
|
|
127
|
-
value: void 0
|
|
85
|
+
value: false
|
|
128
86
|
});
|
|
129
|
-
Object.defineProperty(this, "
|
|
87
|
+
Object.defineProperty(this, "isReconnect", {
|
|
130
88
|
enumerable: true,
|
|
131
89
|
configurable: true,
|
|
132
90
|
writable: true,
|
|
133
91
|
value: false
|
|
134
92
|
});
|
|
135
|
-
|
|
93
|
+
// Only updated after the full connection flow completes not during bond handling.
|
|
94
|
+
Object.defineProperty(this, "serviceIds", {
|
|
136
95
|
enumerable: true,
|
|
137
96
|
configurable: true,
|
|
138
97
|
writable: true,
|
|
139
|
-
value:
|
|
98
|
+
value: new Set()
|
|
140
99
|
});
|
|
141
|
-
Object.defineProperty(this, "
|
|
100
|
+
Object.defineProperty(this, "accelerometer", {
|
|
142
101
|
enumerable: true,
|
|
143
102
|
configurable: true,
|
|
144
103
|
writable: true,
|
|
145
104
|
value: void 0
|
|
146
105
|
});
|
|
147
|
-
Object.defineProperty(this, "
|
|
106
|
+
Object.defineProperty(this, "buttons", {
|
|
148
107
|
enumerable: true,
|
|
149
108
|
configurable: true,
|
|
150
109
|
writable: true,
|
|
151
|
-
value:
|
|
152
|
-
"accelerometerdatachanged",
|
|
153
|
-
])
|
|
110
|
+
value: void 0
|
|
154
111
|
});
|
|
155
|
-
Object.defineProperty(this, "
|
|
112
|
+
Object.defineProperty(this, "deviceInformation", {
|
|
156
113
|
enumerable: true,
|
|
157
114
|
configurable: true,
|
|
158
115
|
writable: true,
|
|
159
|
-
value:
|
|
160
|
-
"buttonachanged",
|
|
161
|
-
"buttonbchanged",
|
|
162
|
-
])
|
|
116
|
+
value: void 0
|
|
163
117
|
});
|
|
164
118
|
Object.defineProperty(this, "led", {
|
|
165
119
|
enumerable: true,
|
|
166
120
|
configurable: true,
|
|
167
121
|
writable: true,
|
|
168
|
-
value:
|
|
122
|
+
value: void 0
|
|
169
123
|
});
|
|
170
124
|
Object.defineProperty(this, "magnetometer", {
|
|
171
125
|
enumerable: true,
|
|
172
126
|
configurable: true,
|
|
173
127
|
writable: true,
|
|
174
|
-
value:
|
|
175
|
-
"magnetometerdatachanged",
|
|
176
|
-
])
|
|
128
|
+
value: void 0
|
|
177
129
|
});
|
|
178
130
|
Object.defineProperty(this, "uart", {
|
|
179
131
|
enumerable: true,
|
|
180
132
|
configurable: true,
|
|
181
133
|
writable: true,
|
|
182
|
-
value:
|
|
134
|
+
value: void 0
|
|
183
135
|
});
|
|
184
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Only defined after connection.
|
|
138
|
+
*/
|
|
139
|
+
Object.defineProperty(this, "boardVersion", {
|
|
185
140
|
enumerable: true,
|
|
186
141
|
configurable: true,
|
|
187
142
|
writable: true,
|
|
188
|
-
value:
|
|
189
|
-
this.accelerometer,
|
|
190
|
-
this.buttons,
|
|
191
|
-
this.led,
|
|
192
|
-
this.magnetometer,
|
|
193
|
-
this.uart,
|
|
194
|
-
]
|
|
143
|
+
value: void 0
|
|
195
144
|
});
|
|
196
|
-
Object.defineProperty(this, "
|
|
145
|
+
Object.defineProperty(this, "services", {
|
|
197
146
|
enumerable: true,
|
|
198
147
|
configurable: true,
|
|
199
148
|
writable: true,
|
|
200
149
|
value: void 0
|
|
201
150
|
});
|
|
202
|
-
Object.defineProperty(this, "
|
|
151
|
+
Object.defineProperty(this, "waitingForDisconnectEventCallbacks", {
|
|
203
152
|
enumerable: true,
|
|
204
153
|
configurable: true,
|
|
205
154
|
writable: true,
|
|
206
|
-
value:
|
|
207
|
-
return new device_js_1.DeviceError({
|
|
208
|
-
code: "device-disconnected",
|
|
209
|
-
message: "Error processing gatt operations queue - device disconnected",
|
|
210
|
-
});
|
|
211
|
-
}
|
|
155
|
+
value: []
|
|
212
156
|
});
|
|
213
|
-
Object.defineProperty(this, "
|
|
157
|
+
Object.defineProperty(this, "internalNotificationListeners", {
|
|
214
158
|
enumerable: true,
|
|
215
159
|
configurable: true,
|
|
216
160
|
writable: true,
|
|
217
|
-
value: new
|
|
218
|
-
abortCheck: () => {
|
|
219
|
-
if (!this.device.gatt?.connected) {
|
|
220
|
-
return this.disconnectedRejectionErrorFactory;
|
|
221
|
-
}
|
|
222
|
-
return undefined;
|
|
223
|
-
},
|
|
224
|
-
})
|
|
161
|
+
value: new Map()
|
|
225
162
|
});
|
|
226
163
|
Object.defineProperty(this, "handleDisconnectEvent", {
|
|
227
164
|
enumerable: true,
|
|
228
165
|
configurable: true,
|
|
229
166
|
writable: true,
|
|
230
167
|
value: async () => {
|
|
168
|
+
this.waitingForDisconnectEventCallbacks.forEach((cb) => cb());
|
|
169
|
+
this.waitingForDisconnectEventCallbacks.length = 0;
|
|
170
|
+
this.connected = false;
|
|
231
171
|
try {
|
|
232
172
|
if (!this.duringExplicitConnectDisconnect) {
|
|
233
|
-
this.logging.log("Bluetooth
|
|
234
|
-
// stateOnReconnectionAttempt();
|
|
235
|
-
this.disposeServices();
|
|
173
|
+
this.logging.log("Bluetooth disconnected... automatically trying reconnect");
|
|
236
174
|
await this.reconnect();
|
|
237
175
|
}
|
|
238
176
|
else {
|
|
239
|
-
this.logging.log("Bluetooth
|
|
177
|
+
this.logging.log("Bluetooth disconnect ignored during explicit disconnect");
|
|
240
178
|
}
|
|
241
179
|
}
|
|
242
180
|
catch (e) {
|
|
@@ -244,21 +182,25 @@ class BluetoothDeviceWrapper {
|
|
|
244
182
|
}
|
|
245
183
|
}
|
|
246
184
|
});
|
|
247
|
-
device.
|
|
185
|
+
this.accelerometer = new accelerometer_service_js_1.AccelerometerService(device.deviceId, dispatchTypedEvent);
|
|
186
|
+
this.buttons = new button_service_js_1.ButtonService(device.deviceId, dispatchTypedEvent);
|
|
187
|
+
this.deviceInformation = new device_information_service_js_1.DeviceInformationService(device.deviceId);
|
|
188
|
+
this.led = new led_service_js_1.LedService(device.deviceId);
|
|
189
|
+
this.magnetometer = new magnetometer_service_js_1.MagnetometerService(device.deviceId, dispatchTypedEvent);
|
|
190
|
+
this.uart = new uart_service_js_1.UARTService(device.deviceId, dispatchTypedEvent);
|
|
191
|
+
this.services = [
|
|
192
|
+
this.accelerometer,
|
|
193
|
+
this.buttons,
|
|
194
|
+
this.led,
|
|
195
|
+
this.magnetometer,
|
|
196
|
+
this.uart,
|
|
197
|
+
];
|
|
248
198
|
}
|
|
249
199
|
async connect() {
|
|
250
200
|
this.logging.event({
|
|
251
201
|
type: this.isReconnect ? "Reconnect" : "Connect",
|
|
252
202
|
message: "Bluetooth connect start",
|
|
253
203
|
});
|
|
254
|
-
if (this.duringExplicitConnectDisconnect) {
|
|
255
|
-
this.logging.log("Skipping connect attempt when one is already in progress");
|
|
256
|
-
// Wait for the gattConnectPromise while showing a "connecting" dialog.
|
|
257
|
-
// If the user clicks disconnect while the automatic reconnect is in progress,
|
|
258
|
-
// then clicks reconnect, we need to wait rather than return immediately.
|
|
259
|
-
await this.gattConnectPromise;
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
204
|
if (this.isReconnect) {
|
|
263
205
|
this.callbacks.onReconnecting();
|
|
264
206
|
}
|
|
@@ -266,70 +208,19 @@ class BluetoothDeviceWrapper {
|
|
|
266
208
|
this.callbacks.onConnecting();
|
|
267
209
|
}
|
|
268
210
|
this.duringExplicitConnectDisconnect++;
|
|
269
|
-
if (this.device.gatt === undefined) {
|
|
270
|
-
throw new Error("BluetoothRemoteGATTServer for micro:bit device is undefined");
|
|
271
|
-
}
|
|
272
|
-
if (isWindowsOS) {
|
|
273
|
-
// On Windows, the micro:bit can take around 3 seconds to respond to gatt.disconnect().
|
|
274
|
-
// Attempting to connect/reconnect before the micro:bit has responded results in another
|
|
275
|
-
// gattserverdisconnected event being fired. We then fail to get primaryService on a
|
|
276
|
-
// disconnected GATT server.
|
|
277
|
-
await this.connectReadyPromise;
|
|
278
|
-
}
|
|
279
211
|
try {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
this.gattConnectPromise =
|
|
283
|
-
this.gattConnectPromise ??
|
|
284
|
-
this.device.gatt
|
|
285
|
-
.connect()
|
|
286
|
-
.then(async () => {
|
|
287
|
-
// We always do this even if we might immediately disconnect as disconnecting
|
|
288
|
-
// without using services causes getPrimaryService calls to hang on subsequent
|
|
289
|
-
// reconnect - probably a device-side issue.
|
|
290
|
-
this.boardVersion = await this.getBoardVersion();
|
|
291
|
-
// This connection could be arbitrarily later when our manual timeout may have passed.
|
|
292
|
-
// Do we still want to be connected?
|
|
293
|
-
if (!this.connecting) {
|
|
294
|
-
this.logging.log("Bluetooth GATT server connect after timeout, triggering disconnect");
|
|
295
|
-
this.disconnectPromise = (async () => {
|
|
296
|
-
await this.disconnectInternal(false);
|
|
297
|
-
this.disconnectPromise = undefined;
|
|
298
|
-
})();
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
this.logging.log("Bluetooth GATT server connected when connecting");
|
|
302
|
-
}
|
|
303
|
-
})
|
|
304
|
-
.catch((e) => {
|
|
305
|
-
if (this.connecting) {
|
|
306
|
-
// Error will be logged by main connect error handling.
|
|
307
|
-
throw e;
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
this.logging.error("Bluetooth GATT server connect error after our timeout", e);
|
|
311
|
-
return undefined;
|
|
312
|
-
}
|
|
313
|
-
})
|
|
314
|
-
.finally(() => {
|
|
315
|
-
this.logging.log("Bluetooth GATT server promise field cleared");
|
|
316
|
-
this.gattConnectPromise = undefined;
|
|
317
|
-
});
|
|
318
|
-
this.connecting = true;
|
|
319
|
-
try {
|
|
320
|
-
const gattConnectResult = await Promise.race([
|
|
321
|
-
this.gattConnectPromise,
|
|
322
|
-
new Promise((resolve) => setTimeout(() => resolve("timeout"), connectTimeoutDuration)),
|
|
323
|
-
]);
|
|
324
|
-
if (gattConnectResult === "timeout") {
|
|
325
|
-
this.logging.log("Bluetooth GATT server connect timeout");
|
|
326
|
-
throw new Error("Bluetooth GATT server connect timeout");
|
|
327
|
-
}
|
|
212
|
+
if (core_1.Capacitor.isNativePlatform()) {
|
|
213
|
+
await this.connectHandlingBond();
|
|
328
214
|
}
|
|
329
|
-
|
|
330
|
-
this.
|
|
215
|
+
else {
|
|
216
|
+
await this.connectInternal();
|
|
331
217
|
}
|
|
332
|
-
|
|
218
|
+
await this.getBoardVersion();
|
|
219
|
+
const events = this.currentEvents();
|
|
220
|
+
const services = await bluetooth_le_1.BleClient.getServices(this.device.deviceId);
|
|
221
|
+
this.serviceIds = new Set(services.map((s) => s.uuid));
|
|
222
|
+
this.logging.log(`Starting notifications for current events ${events}`);
|
|
223
|
+
events.forEach((e) => this.startNotifications(e));
|
|
333
224
|
this.logging.event({
|
|
334
225
|
type: this.isReconnect ? "Reconnect" : "Connect",
|
|
335
226
|
message: "Bluetooth connect success",
|
|
@@ -344,7 +235,19 @@ class BluetoothDeviceWrapper {
|
|
|
344
235
|
});
|
|
345
236
|
await this.disconnectInternal(false);
|
|
346
237
|
this.callbacks.onFail();
|
|
347
|
-
|
|
238
|
+
if (e instanceof device_js_1.DeviceError) {
|
|
239
|
+
throw e;
|
|
240
|
+
}
|
|
241
|
+
if (e instanceof async_util_js_1.TimeoutError) {
|
|
242
|
+
throw new device_js_1.DeviceError({
|
|
243
|
+
code: "timeout-error",
|
|
244
|
+
message: e instanceof Error ? e.message : String(e),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
throw new device_js_1.DeviceError({
|
|
248
|
+
code: "bluetooth-connection-failed",
|
|
249
|
+
message: e instanceof Error ? e.message : String(e),
|
|
250
|
+
});
|
|
348
251
|
}
|
|
349
252
|
finally {
|
|
350
253
|
this.duringExplicitConnectDisconnect--;
|
|
@@ -352,6 +255,13 @@ class BluetoothDeviceWrapper {
|
|
|
352
255
|
this.isReconnect = false;
|
|
353
256
|
}
|
|
354
257
|
}
|
|
258
|
+
async connectInternal() {
|
|
259
|
+
this.waitingForDisconnectEventCallbacks.length = 0;
|
|
260
|
+
await bluetooth_le_1.BleClient.connect(this.device.deviceId, this.handleDisconnectEvent, {
|
|
261
|
+
timeout: exports.connectTimeoutInMs,
|
|
262
|
+
});
|
|
263
|
+
this.connected = true;
|
|
264
|
+
}
|
|
355
265
|
async disconnect() {
|
|
356
266
|
return this.disconnectInternal(true);
|
|
357
267
|
}
|
|
@@ -359,8 +269,8 @@ class BluetoothDeviceWrapper {
|
|
|
359
269
|
this.logging.log(`Bluetooth disconnect ${userTriggered ? "(user triggered)" : "(programmatic)"}`);
|
|
360
270
|
this.duringExplicitConnectDisconnect++;
|
|
361
271
|
try {
|
|
362
|
-
if (this.
|
|
363
|
-
this.device.
|
|
272
|
+
if (this.connected) {
|
|
273
|
+
await bluetooth_le_1.BleClient.disconnect(this.device.deviceId);
|
|
364
274
|
}
|
|
365
275
|
}
|
|
366
276
|
catch (e) {
|
|
@@ -368,100 +278,209 @@ class BluetoothDeviceWrapper {
|
|
|
368
278
|
// We might have already lost the connection.
|
|
369
279
|
}
|
|
370
280
|
finally {
|
|
371
|
-
this.disposeServices();
|
|
372
281
|
this.duringExplicitConnectDisconnect--;
|
|
373
282
|
}
|
|
374
|
-
this.connectReadyPromise = new Promise((resolve) => setTimeout(resolve, 3_500));
|
|
375
283
|
}
|
|
376
284
|
async reconnect() {
|
|
377
285
|
this.logging.log("Bluetooth reconnect");
|
|
378
286
|
this.isReconnect = true;
|
|
379
287
|
await this.connect();
|
|
380
288
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
289
|
+
async getBoardVersion() {
|
|
290
|
+
// We read this when we connect and it won't change.
|
|
291
|
+
if (this.boardVersion) {
|
|
292
|
+
return this.boardVersion;
|
|
384
293
|
}
|
|
385
|
-
|
|
294
|
+
this.boardVersion = await this.deviceInformation.getBoardVersion();
|
|
295
|
+
return this.boardVersion;
|
|
386
296
|
}
|
|
387
|
-
async
|
|
388
|
-
this.
|
|
389
|
-
|
|
297
|
+
async startNotifications(type) {
|
|
298
|
+
await this.getServicesForEvent(type)?.startNotifications(type);
|
|
299
|
+
}
|
|
300
|
+
async stopNotifications(type) {
|
|
301
|
+
await this.getServicesForEvent(type)?.stopNotifications(type);
|
|
302
|
+
}
|
|
303
|
+
getServicesForEvent(type) {
|
|
304
|
+
return this.services.find((s) => this.serviceIds.has(s.uuid) && s.getRelevantEvents().includes(type));
|
|
305
|
+
}
|
|
306
|
+
async startInternalNotifications(serviceId, characteristicId, options) {
|
|
307
|
+
const key = this.getNotificationKey(serviceId, characteristicId);
|
|
308
|
+
await this.raceDisconnectAndTimeout(bluetooth_le_1.BleClient.startNotifications(this.device.deviceId, serviceId, characteristicId, (value) => {
|
|
309
|
+
const bytes = new Uint8Array(value.buffer);
|
|
310
|
+
// Notify all registered callbacks.
|
|
311
|
+
this.internalNotificationListeners
|
|
312
|
+
.get(key)
|
|
313
|
+
?.forEach((cb) => cb(bytes));
|
|
314
|
+
}, options), { actionName: "start notifications" });
|
|
315
|
+
}
|
|
316
|
+
subscribe(serviceId, characteristicId, callback) {
|
|
317
|
+
const key = this.getNotificationKey(serviceId, characteristicId);
|
|
318
|
+
if (!this.internalNotificationListeners.has(key)) {
|
|
319
|
+
this.internalNotificationListeners.set(key, new Set());
|
|
320
|
+
}
|
|
321
|
+
this.internalNotificationListeners.get(key).add(callback);
|
|
322
|
+
}
|
|
323
|
+
unsubscribe(serviceId, characteristicId, callback) {
|
|
324
|
+
const key = this.getNotificationKey(serviceId, characteristicId);
|
|
325
|
+
this.internalNotificationListeners.get(key)?.delete(callback);
|
|
326
|
+
}
|
|
327
|
+
async stopInternalNotifications(serviceId, characteristicId) {
|
|
328
|
+
await bluetooth_le_1.BleClient.stopNotifications(this.device.deviceId, serviceId, characteristicId);
|
|
329
|
+
const key = this.getNotificationKey(serviceId, characteristicId);
|
|
330
|
+
this.internalNotificationListeners.delete(key);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Write to characteristic and wait for a notification response.
|
|
334
|
+
*
|
|
335
|
+
* It is the responsibility of the caller to have started notifications
|
|
336
|
+
* for the characteristic.
|
|
337
|
+
*/
|
|
338
|
+
async writeForNotification(serviceId, characteristicId, value, notificationId, isFinalNotification = () => true) {
|
|
339
|
+
let notificationListener;
|
|
340
|
+
const notificationPromise = new Promise((resolve) => {
|
|
341
|
+
notificationListener = (bytes) => {
|
|
342
|
+
if (bytes[0] === notificationId && isFinalNotification(bytes)) {
|
|
343
|
+
resolve(bytes);
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
this.subscribe(serviceId, characteristicId, notificationListener);
|
|
347
|
+
});
|
|
390
348
|
try {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (
|
|
399
|
-
|
|
349
|
+
await bluetooth_le_1.BleClient.writeWithoutResponse(this.device.deviceId, serviceId, characteristicId, value);
|
|
350
|
+
return await this.raceDisconnectAndTimeout(notificationPromise, {
|
|
351
|
+
timeout: 3_000,
|
|
352
|
+
actionName: "flash notification wait",
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
finally {
|
|
356
|
+
if (notificationListener) {
|
|
357
|
+
this.unsubscribe(serviceId, characteristicId, notificationListener);
|
|
400
358
|
}
|
|
401
|
-
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
async waitForDisconnect(timeout) {
|
|
362
|
+
if (!this.connected) {
|
|
363
|
+
this.log("Waiting for disconnect but not connected");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
this.log(`Waiting for disconnect (timeout ${timeout})`);
|
|
367
|
+
try {
|
|
368
|
+
await Promise.race([
|
|
369
|
+
this.disconnectErrorPromise("wait"),
|
|
370
|
+
(0, async_util_js_1.timeoutErrorAfter)(timeout),
|
|
371
|
+
]);
|
|
402
372
|
}
|
|
403
373
|
catch (e) {
|
|
404
|
-
|
|
405
|
-
|
|
374
|
+
if (e instanceof async_util_js_1.TimeoutError) {
|
|
375
|
+
this.error("Timeout waiting for disconnect");
|
|
376
|
+
}
|
|
377
|
+
if (!(e instanceof async_util_js_1.DisconnectError)) {
|
|
378
|
+
throw e;
|
|
379
|
+
}
|
|
406
380
|
}
|
|
407
381
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
382
|
+
/**
|
|
383
|
+
* Suitable for running a series of BLE interactions with an overall timeout
|
|
384
|
+
* and general disconnection
|
|
385
|
+
*/
|
|
386
|
+
async raceDisconnectAndTimeout(promise, options = {}) {
|
|
387
|
+
if (!this.connected) {
|
|
388
|
+
throw new async_util_js_1.DisconnectError();
|
|
389
|
+
}
|
|
390
|
+
const actionName = options.actionName ?? "action";
|
|
391
|
+
const errorOnDisconnectPromise = this.disconnectErrorPromise(actionName);
|
|
392
|
+
return await Promise.race([
|
|
393
|
+
promise,
|
|
394
|
+
errorOnDisconnectPromise,
|
|
395
|
+
...(options.timeout ? [(0, async_util_js_1.timeoutErrorAfter)(options.timeout)] : []),
|
|
396
|
+
]);
|
|
412
397
|
}
|
|
413
|
-
|
|
414
|
-
const
|
|
415
|
-
|
|
398
|
+
disconnectErrorPromise(actionName) {
|
|
399
|
+
const { promise, callback } = (0, async_util_js_1.disconnectErrorCallback)(`Disconnected during ${actionName}`);
|
|
400
|
+
this.waitingForDisconnectEventCallbacks.push(callback);
|
|
401
|
+
return promise;
|
|
416
402
|
}
|
|
417
|
-
|
|
418
|
-
|
|
403
|
+
event(event) {
|
|
404
|
+
this.logging.event(event);
|
|
419
405
|
}
|
|
420
|
-
|
|
421
|
-
|
|
406
|
+
log(message) {
|
|
407
|
+
this.logging.log(message);
|
|
422
408
|
}
|
|
423
|
-
|
|
424
|
-
|
|
409
|
+
error(message, e) {
|
|
410
|
+
this.logging.error(message, e);
|
|
425
411
|
}
|
|
426
|
-
|
|
427
|
-
return
|
|
412
|
+
getNotificationKey(serviceId, characteristicId) {
|
|
413
|
+
return `${serviceId}:${characteristicId}`;
|
|
428
414
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
415
|
+
/**
|
|
416
|
+
* Bonds with device and handles the post-bond device state only returning
|
|
417
|
+
* when we can reattempt a connection with the device.
|
|
418
|
+
*/
|
|
419
|
+
async connectHandlingBond() {
|
|
420
|
+
const startTime = Date.now();
|
|
421
|
+
const maybeJustBonded = await this.bondConnectDeviceInternal();
|
|
422
|
+
if (maybeJustBonded) {
|
|
423
|
+
// If we did just bond then the device disconnects after 2_000 and then
|
|
424
|
+
// resets after a further 13_000 In future we'd like a firmware change
|
|
425
|
+
// that means it doesn't reset when partial flashing is in progress.
|
|
426
|
+
this.log((0, exports.isAndroid)() ? "New bond" : "Potential new bond");
|
|
427
|
+
// On Android with micro:bit V1 we don't see this disconnect (just the 15s
|
|
428
|
+
// reboot) so we hit the timeout and then continue to reset into pairing
|
|
429
|
+
// mode.
|
|
430
|
+
// TODO: document what happens with iOS micro:bit V1 in the new bond case.
|
|
431
|
+
try {
|
|
432
|
+
await this.waitForDisconnect(3000);
|
|
433
|
+
}
|
|
434
|
+
catch (e) {
|
|
435
|
+
if (e instanceof async_util_js_1.TimeoutError) {
|
|
436
|
+
this.log("No disconnect after bond, assuming connection is stable");
|
|
437
|
+
if (!(0, exports.isAndroid)()) {
|
|
438
|
+
// We never knew for sure whether this was a new bond. Assume we
|
|
439
|
+
// were already bonded on the basis we didn't get disconnected.
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
throw e;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
await this.connectInternal();
|
|
448
|
+
// TODO: check this is needed, potentially inline into connect if always needed
|
|
449
|
+
await (0, async_util_js_1.delay)(500);
|
|
450
|
+
this.log("Resetting to pairing mode");
|
|
451
|
+
const pf = new partial_flashing_service_js_1.PartialFlashingService(this);
|
|
452
|
+
await pf.resetToMode(partial_flashing_service_js_1.MicroBitMode.Pairing);
|
|
453
|
+
await this.waitForDisconnect(10_000);
|
|
454
|
+
await this.connectInternal();
|
|
455
|
+
this.log(`Connection ready; took ${Date.now() - startTime}`);
|
|
437
456
|
}
|
|
438
457
|
}
|
|
439
|
-
async
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
458
|
+
async bondConnectDeviceInternal() {
|
|
459
|
+
const { deviceId } = this.device;
|
|
460
|
+
if ((0, exports.isAndroid)()) {
|
|
461
|
+
let justBonded = false;
|
|
462
|
+
// This gets us a nicer pairing dialog than just going straight for the characteristic.
|
|
463
|
+
if (!(await bluetooth_le_1.BleClient.isBonded(deviceId))) {
|
|
464
|
+
await bluetooth_le_1.BleClient.createBond(deviceId, { timeout: exports.bondingTimeoutInMs });
|
|
465
|
+
justBonded = true;
|
|
466
|
+
}
|
|
467
|
+
await this.connectInternal();
|
|
468
|
+
return justBonded;
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
// Long timeout as this is the point that the pairing dialog will show.
|
|
472
|
+
// If this responds very quickly maybe we could assume there was a bond?
|
|
473
|
+
// At the moment we always do the disconnect dance so subsequent code will
|
|
474
|
+
// need to call startNotifications again. We need to be connected to
|
|
475
|
+
// startNotifications.
|
|
476
|
+
await this.connectInternal();
|
|
477
|
+
const pf = new partial_flashing_service_js_1.PartialFlashingService(this);
|
|
478
|
+
await pf.startNotifications({ timeout: exports.bondingTimeoutInMs });
|
|
479
|
+
// We just did it now to trigger pairing at a well defined point.
|
|
480
|
+
await pf.stopNotifications();
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
448
483
|
}
|
|
449
484
|
}
|
|
450
485
|
exports.BluetoothDeviceWrapper = BluetoothDeviceWrapper;
|
|
451
|
-
const createBluetoothDeviceWrapper = async (device, logging, dispatchTypedEvent, currentEvents, callbacks) => {
|
|
452
|
-
try {
|
|
453
|
-
// Reuse our connection objects for the same device as they
|
|
454
|
-
// track the GATT connect promise that never resolves.
|
|
455
|
-
const bluetooth = deviceIdToWrapper.get(device.id) ??
|
|
456
|
-
new BluetoothDeviceWrapper(device, logging, dispatchTypedEvent, currentEvents, callbacks);
|
|
457
|
-
deviceIdToWrapper.set(device.id, bluetooth);
|
|
458
|
-
await bluetooth.connect();
|
|
459
|
-
return bluetooth;
|
|
460
|
-
}
|
|
461
|
-
catch (e) {
|
|
462
|
-
logging.error("Bluetooth connect error", e);
|
|
463
|
-
return undefined;
|
|
464
|
-
}
|
|
465
|
-
};
|
|
466
|
-
exports.createBluetoothDeviceWrapper = createBluetoothDeviceWrapper;
|
|
467
486
|
//# sourceMappingURL=bluetooth-device-wrapper.js.map
|