mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-12 01:23:52 +00:00
120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
import { Action } from 'redux';
|
|
import { ThunkAction } from 'redux-thunk';
|
|
|
|
const pybricksServiceUUID = 'c5f50001-8280-46da-89f4-6d8051e4aeef';
|
|
const bleNusServiceUUID = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
|
|
const bleNusCharRXUUID = '6e400002-b5a3-f393-e0a9-e50e24dcca9e';
|
|
const bleNusCharTXUUID = '6e400003-b5a3-f393-e0a9-e50e24dcca9e';
|
|
|
|
let device: BluetoothDevice | undefined;
|
|
let rxChar: BluetoothRemoteGATTCharacteristic | undefined;
|
|
|
|
export enum BLEConnectActionType {
|
|
/**
|
|
* Begin async connect.
|
|
*/
|
|
BeginConnect = 'ble.connect.begin',
|
|
/**
|
|
* End async connect (success).
|
|
*/
|
|
EndConnect = 'ble.connect.end',
|
|
/**
|
|
* Begin async disconnect.
|
|
*/
|
|
BeginDisconnect = 'ble.disconnect.begin',
|
|
/**
|
|
* End async disconnect (can be sent without sending BeginDisconnect first).
|
|
*/
|
|
EndDisconnect = 'ble.disconnect.end',
|
|
}
|
|
|
|
type BLEConnectAction = Action<BLEConnectActionType>;
|
|
|
|
enum BLEDataActionType {
|
|
/**
|
|
* Send data.
|
|
*/
|
|
SendData = 'ble.data.send',
|
|
/**
|
|
* Data was received.
|
|
*/
|
|
ReceivedData = 'ble.data.receive',
|
|
}
|
|
|
|
interface BLEDataAction extends Action<BLEDataActionType> {
|
|
value: DataView;
|
|
}
|
|
|
|
type AnyBLEAction = BLEConnectAction | BLEDataAction;
|
|
|
|
type BLEThunkAction = ThunkAction<Promise<void>, {}, {}, AnyBLEAction>;
|
|
|
|
function beginConnect(): BLEConnectAction {
|
|
return { type: BLEConnectActionType.BeginConnect };
|
|
}
|
|
|
|
function endConnect(): BLEConnectAction {
|
|
return { type: BLEConnectActionType.EndConnect };
|
|
}
|
|
|
|
function beginDisconnect(): BLEConnectAction {
|
|
return { type: BLEConnectActionType.BeginDisconnect };
|
|
}
|
|
|
|
function endDisconnect(): BLEConnectAction {
|
|
return { type: BLEConnectActionType.EndDisconnect };
|
|
}
|
|
|
|
export function connect(): BLEThunkAction {
|
|
return async function (dispatch): Promise<void> {
|
|
if (device !== undefined) {
|
|
console.error('Already have a connected device');
|
|
return;
|
|
}
|
|
if (navigator.bluetooth === undefined) {
|
|
// TODO: dispatch error toast action
|
|
console.error('Browser does not support WebBluetooth or it is not enabled');
|
|
return;
|
|
}
|
|
dispatch(beginConnect());
|
|
device = await navigator.bluetooth.requestDevice({
|
|
filters: [{ services: [pybricksServiceUUID] }],
|
|
optionalServices: [bleNusServiceUUID],
|
|
});
|
|
if (device.gatt === undefined) {
|
|
console.error('Device does not support GATT');
|
|
return;
|
|
}
|
|
device.addEventListener('gattserverdisconnected', () => {
|
|
device = undefined;
|
|
rxChar = undefined;
|
|
dispatch(endDisconnect());
|
|
});
|
|
const server = await device.gatt.connect();
|
|
try {
|
|
const service = await server.getPrimaryService(bleNusServiceUUID);
|
|
rxChar = await service.getCharacteristic(bleNusCharRXUUID);
|
|
const txChar = await service.getCharacteristic(bleNusCharTXUUID);
|
|
txChar.addEventListener('characteristicvaluechanged', () => {
|
|
if (!txChar.value) {
|
|
return;
|
|
}
|
|
dispatch({ type: BLEDataActionType.ReceivedData, value: txChar.value });
|
|
});
|
|
await txChar.startNotifications();
|
|
} catch (err) {
|
|
console.error('getting nRF UART service failed');
|
|
device.gatt.disconnect();
|
|
return;
|
|
}
|
|
dispatch(endConnect());
|
|
};
|
|
}
|
|
|
|
export function disconnect(): BLEThunkAction {
|
|
return async function (dispatch): Promise<void> {
|
|
dispatch(beginDisconnect());
|
|
device?.gatt?.disconnect();
|
|
};
|
|
}
|