mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-14 18:46:17 +00:00
Add Device Information Service support
The Pybricks firmware now includes the BLE Device Information Service to provide firmware and Pybricks protocol versions. For now, checking that the service is present is enough to know that the firmware is up to date. But we will need to add additional checks as soon as the protocol is changed.
This commit is contained in:
+87
-3
@@ -15,6 +15,11 @@ import {
|
||||
takeEvery,
|
||||
takeMaybe,
|
||||
} from 'typed-redux-saga/macro';
|
||||
import {
|
||||
serviceUUID as deviceInfoServiceUUID,
|
||||
firmwareRevisionStringUUID,
|
||||
softwareRevisionStringUUID,
|
||||
} from '../ble-device-info-service/protocol';
|
||||
import {
|
||||
BlePybricksServiceActionType,
|
||||
didFailToWriteCommand,
|
||||
@@ -53,6 +58,8 @@ import {
|
||||
TxCharUUID as uartTxCharUUID,
|
||||
} from './protocol';
|
||||
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
function disconnect(
|
||||
server: BluetoothRemoteGATTServer,
|
||||
_action: BleDeviceDisconnectAction,
|
||||
@@ -109,7 +116,11 @@ function* connect(_action: BleDeviceConnectAction): Generator {
|
||||
device = yield* call(() =>
|
||||
navigator.bluetooth.requestDevice({
|
||||
filters: [{ services: [pybricksServiceUUID] }],
|
||||
optionalServices: [pybricksServiceUUID, uartServiceUUID],
|
||||
optionalServices: [
|
||||
pybricksServiceUUID,
|
||||
deviceInfoServiceUUID,
|
||||
uartServiceUUID,
|
||||
],
|
||||
}),
|
||||
);
|
||||
} catch (err) {
|
||||
@@ -145,6 +156,79 @@ function* connect(_action: BleDeviceConnectAction): Generator {
|
||||
|
||||
yield* takeEvery(BLEDeviceActionType.Disconnect, disconnect, server);
|
||||
|
||||
let deviceInfoService: BluetoothRemoteGATTService;
|
||||
try {
|
||||
deviceInfoService = yield* call(
|
||||
[server, 'getPrimaryService'],
|
||||
deviceInfoServiceUUID,
|
||||
);
|
||||
} catch (err) {
|
||||
server.disconnect();
|
||||
yield* takeMaybe(disconnectChannel);
|
||||
if (err instanceof DOMException && err.code === DOMException.NOT_FOUND_ERR) {
|
||||
yield* put(didFailToConnect({ reason: Reason.NoDeviceInfoService }));
|
||||
} else {
|
||||
yield* put(didFailToConnect({ reason: Reason.Unknown, err }));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let firmwareVersionChar: BluetoothRemoteGATTCharacteristic;
|
||||
try {
|
||||
firmwareVersionChar = yield* call(
|
||||
[deviceInfoService, 'getCharacteristic'],
|
||||
firmwareRevisionStringUUID,
|
||||
);
|
||||
} catch (err) {
|
||||
server.disconnect();
|
||||
yield* takeMaybe(disconnectChannel);
|
||||
yield* put(didFailToConnect({ reason: Reason.Unknown, err }));
|
||||
return;
|
||||
}
|
||||
|
||||
let firmwareVersion: string;
|
||||
try {
|
||||
firmwareVersion = decoder.decode(
|
||||
yield* call([firmwareVersionChar, 'readValue']),
|
||||
);
|
||||
} catch (err) {
|
||||
server.disconnect();
|
||||
yield* takeMaybe(disconnectChannel);
|
||||
yield* put(didFailToConnect({ reason: Reason.Unknown, err }));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: save firmware version for later use
|
||||
console.log(`Hub firmware version: ${firmwareVersion}`);
|
||||
|
||||
let softwareVersionChar: BluetoothRemoteGATTCharacteristic;
|
||||
try {
|
||||
softwareVersionChar = yield* call(
|
||||
[deviceInfoService, 'getCharacteristic'],
|
||||
softwareRevisionStringUUID,
|
||||
);
|
||||
} catch (err) {
|
||||
server.disconnect();
|
||||
yield* takeMaybe(disconnectChannel);
|
||||
yield* put(didFailToConnect({ reason: Reason.Unknown, err }));
|
||||
return;
|
||||
}
|
||||
|
||||
let protocolVersion: string;
|
||||
try {
|
||||
protocolVersion = decoder.decode(
|
||||
yield* call([softwareVersionChar, 'readValue']),
|
||||
);
|
||||
} catch (err) {
|
||||
server.disconnect();
|
||||
yield* takeMaybe(disconnectChannel);
|
||||
yield* put(didFailToConnect({ reason: Reason.Unknown, err }));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: verify that minimum protocol version is met
|
||||
console.log(`Pybricks protocol version: ${protocolVersion}`);
|
||||
|
||||
let pybricksService: BluetoothRemoteGATTService;
|
||||
try {
|
||||
pybricksService = yield* call(
|
||||
@@ -155,7 +239,7 @@ function* connect(_action: BleDeviceConnectAction): Generator {
|
||||
server.disconnect();
|
||||
yield* takeMaybe(disconnectChannel);
|
||||
if (err instanceof DOMException && err.code === DOMException.NOT_FOUND_ERR) {
|
||||
yield* put(didFailToConnect({ reason: Reason.NoService }));
|
||||
yield* put(didFailToConnect({ reason: Reason.NoPybricksService }));
|
||||
} else {
|
||||
yield* put(didFailToConnect({ reason: Reason.Unknown, err }));
|
||||
}
|
||||
@@ -231,7 +315,7 @@ function* connect(_action: BleDeviceConnectAction): Generator {
|
||||
server.disconnect();
|
||||
yield* takeMaybe(disconnectChannel);
|
||||
if (err instanceof DOMException && err.code === DOMException.NOT_FOUND_ERR) {
|
||||
yield* put(didFailToConnect({ reason: Reason.NoService }));
|
||||
yield* put(didFailToConnect({ reason: Reason.NoPybricksService }));
|
||||
} else {
|
||||
yield* put(didFailToConnect({ reason: Reason.Unknown, err }));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user