239 lines
11 KiB
Plaintext
239 lines
11 KiB
Plaintext
import * as BluetoothManager from './bluetooth_manager.uts';
|
||
import { ServiceManager } from './service_manager.uts';
|
||
import type { ScanDevicesOptions, BleConnectOptionsExt, MultiProtocolDevice, BleEvent, BleEventCallback, BleService, BleCharacteristic, WriteCharacteristicOptions, AutoBleInterfaces, BleDataReceivedCallback, BleProtocolType, BluetoothService as BluetoothServiceContract } from '../interface.uts';
|
||
import { DeviceManager } from './device_manager.uts';
|
||
|
||
const serviceManager = ServiceManager.getInstance();
|
||
|
||
class AndroidBluetoothService implements BluetoothServiceContract {
|
||
scanDevices(options?: ScanDevicesOptions | null): Promise<void> {
|
||
return BluetoothManager.scanDevices(options);
|
||
}
|
||
async connectDevice(deviceId: string, protocol?: string, options?: BleConnectOptionsExt | null): Promise<void> {
|
||
const proto = (protocol != null && protocol !== '') ? (protocol as BleProtocolType) : 'standard';
|
||
return BluetoothManager.connectDevice(deviceId, proto, options ?? null);
|
||
}
|
||
async disconnectDevice(deviceId: string, protocol?: string): Promise<void> {
|
||
const proto = (protocol != null && protocol !== '') ? (protocol as BleProtocolType) : 'standard';
|
||
return BluetoothManager.disconnectDevice(deviceId, proto);
|
||
}
|
||
getConnectedDevices(): MultiProtocolDevice[] {
|
||
return BluetoothManager.getConnectedDevices();
|
||
}
|
||
on(event: BleEvent | string, callback: BleEventCallback): void {
|
||
BluetoothManager.on(event as BleEvent, callback);
|
||
}
|
||
off(event: BleEvent | string, callback?: BleEventCallback | null): void {
|
||
BluetoothManager.off(event as BleEvent, callback ?? null);
|
||
}
|
||
getServices(deviceId: string): Promise<BleService[]> {
|
||
return new Promise((resolve, reject) => {
|
||
serviceManager.getServices(deviceId, (list, err) => {
|
||
console.log('getServices:', list, err);
|
||
if (err != null) {
|
||
reject(err);
|
||
} else {
|
||
resolve((list as BleService[]) ?? []);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
getCharacteristics(deviceId: string, serviceId: string): Promise<BleCharacteristic[]> {
|
||
return new Promise((resolve, reject) => {
|
||
console.log(deviceId, serviceId);
|
||
serviceManager.getCharacteristics(deviceId, serviceId, (list, err) => {
|
||
if (err != null) {
|
||
reject(err);
|
||
} else {
|
||
resolve((list as BleCharacteristic[]) ?? []);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
/**
|
||
* 自动发现服务和特征,返回可用的写入和通知特征ID
|
||
* @param deviceId 设备ID
|
||
* @returns {Promise<AutoBleInterfaces>}
|
||
*/
|
||
async getAutoBleInterfaces(deviceId: string): Promise<AutoBleInterfaces> {
|
||
// 1. 获取服务列表
|
||
const services = await this.getServices(deviceId);
|
||
if (services == null || services.length == 0) throw new Error('未发现服务');
|
||
|
||
// 2. 选择目标服务(优先bae前缀,可根据需要调整)
|
||
let serviceId = '';
|
||
for (let i = 0; i < services.length; i++) {
|
||
const s = services[i];
|
||
const uuidCandidate: string | null = (s.uuid != null ? s.uuid : null)
|
||
const uuid: string = uuidCandidate != null ? uuidCandidate : ''
|
||
// prefer regex test to avoid nullable receiver calls in generated Kotlin
|
||
if (/^bae/i.test(uuid)) {
|
||
serviceId = uuid
|
||
break;
|
||
}
|
||
}
|
||
console.log(serviceId)
|
||
if (serviceId == null || serviceId == '') serviceId = services[0].uuid;
|
||
|
||
// 3. 获取特征列表
|
||
const characteristics = await this.getCharacteristics(deviceId, serviceId);
|
||
console.log(characteristics)
|
||
if (characteristics == null || characteristics.length == 0) throw new Error('未发现特征值');
|
||
|
||
// 4. 筛选write和notify特征
|
||
let writeCharId = '';
|
||
let notifyCharId = '';
|
||
for (let i = 0; i < characteristics.length; i++) {
|
||
|
||
const c = characteristics[i];
|
||
console.log(c)
|
||
if ((writeCharId == null || writeCharId == '') && c.properties != null && (c.properties.write || c.properties.writeWithoutResponse==true)) writeCharId = c.uuid;
|
||
if ((notifyCharId == null || notifyCharId == '') && c.properties != null && (c.properties.notify || c.properties.indicate)) notifyCharId = c.uuid;
|
||
}
|
||
console.log(serviceId, writeCharId, notifyCharId);
|
||
if ((writeCharId == null || writeCharId == '') || (notifyCharId == null || notifyCharId == '')) throw new Error('未找到合适的写入或通知特征');
|
||
console.log(serviceId, writeCharId, notifyCharId);
|
||
// // 发现服务和特征后
|
||
const deviceManager = DeviceManager.getInstance();
|
||
console.log(deviceManager);
|
||
const device = deviceManager.getDevice(deviceId);
|
||
console.log(deviceId,device)
|
||
device!.serviceId = serviceId;
|
||
device!.writeCharId = writeCharId;
|
||
device!.notifyCharId = notifyCharId;
|
||
console.log(device);
|
||
return { serviceId, writeCharId, notifyCharId };
|
||
}
|
||
async subscribeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, onData: BleDataReceivedCallback): Promise<void> {
|
||
return serviceManager.subscribeCharacteristic(deviceId, serviceId, characteristicId, onData);
|
||
}
|
||
async readCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<ArrayBuffer> {
|
||
return serviceManager.readCharacteristic(deviceId, serviceId, characteristicId);
|
||
}
|
||
async writeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, value: Uint8Array | ArrayBuffer, options?: WriteCharacteristicOptions): Promise<boolean> {
|
||
const payload = value instanceof Uint8Array ? value : new Uint8Array(value);
|
||
return serviceManager.writeCharacteristic(deviceId, serviceId, characteristicId, payload, options);
|
||
}
|
||
async unsubscribeCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<void> {
|
||
return serviceManager.unsubscribeCharacteristic(deviceId, serviceId, characteristicId);
|
||
}
|
||
async autoDiscoverAll(deviceId: string): Promise<any> {
|
||
return serviceManager.autoDiscoverAll(deviceId);
|
||
}
|
||
async subscribeAllNotifications(deviceId: string, onData: BleDataReceivedCallback): Promise<void> {
|
||
return serviceManager.subscribeAllNotifications(deviceId, onData);
|
||
}
|
||
}
|
||
|
||
export class BluetoothServiceShape implements BluetoothServiceContract {
|
||
scanDevices(options?: ScanDevicesOptions | null): Promise<void> {
|
||
return BluetoothManager.scanDevices(options);
|
||
}
|
||
async connectDevice(deviceId: string, protocol?: string, options?: BleConnectOptionsExt | null): Promise<void> {
|
||
const proto = (protocol != null && protocol !== '') ? (protocol as BleProtocolType) : 'standard';
|
||
return BluetoothManager.connectDevice(deviceId, proto, options ?? null);
|
||
}
|
||
async disconnectDevice(deviceId: string, protocol?: string): Promise<void> {
|
||
const proto = (protocol != null && protocol !== '') ? (protocol as BleProtocolType) : 'standard';
|
||
return BluetoothManager.disconnectDevice(deviceId, proto);
|
||
}
|
||
getConnectedDevices(): MultiProtocolDevice[] {
|
||
return BluetoothManager.getConnectedDevices();
|
||
}
|
||
on(event: BleEvent | string, callback: BleEventCallback): void {
|
||
BluetoothManager.on(event as BleEvent, callback);
|
||
}
|
||
off(event: BleEvent | string, callback?: BleEventCallback | null): void {
|
||
BluetoothManager.off(event as BleEvent, callback ?? null);
|
||
}
|
||
getServices(deviceId: string): Promise<BleService[]> {
|
||
return new Promise((resolve, reject) => {
|
||
serviceManager.getServices(deviceId, (list, err) => {
|
||
console.log('getServices:', list, err);
|
||
if (err != null) {
|
||
reject(err);
|
||
} else {
|
||
resolve((list as BleService[]) ?? []);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
getCharacteristics(deviceId: string, serviceId: string): Promise<BleCharacteristic[]> {
|
||
return new Promise((resolve, reject) => {
|
||
console.log(deviceId, serviceId);
|
||
serviceManager.getCharacteristics(deviceId, serviceId, (list, err) => {
|
||
if (err != null) {
|
||
reject(err);
|
||
} else {
|
||
resolve((list as BleCharacteristic[]) ?? []);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
async getAutoBleInterfaces(deviceId: string): Promise<AutoBleInterfaces> {
|
||
const services = await this.getServices(deviceId);
|
||
if (services == null || services.length == 0) throw new Error('未发现服务');
|
||
|
||
let serviceId = '';
|
||
for (let i = 0; i < services.length; i++) {
|
||
const s = services[i];
|
||
const uuidCandidate: string | null = (s.uuid != null ? s.uuid : null)
|
||
const uuid: string = uuidCandidate != null ? uuidCandidate : ''
|
||
if (/^bae/i.test(uuid)) {
|
||
serviceId = uuid
|
||
break;
|
||
}
|
||
}
|
||
console.log(serviceId)
|
||
if (serviceId == null || serviceId == '') serviceId = services[0].uuid;
|
||
|
||
const characteristics = await this.getCharacteristics(deviceId, serviceId);
|
||
if (characteristics == null || characteristics.length == 0) throw new Error('未发现特征值');
|
||
|
||
let writeCharId = '';
|
||
let notifyCharId = '';
|
||
for (let i = 0; i < characteristics.length; i++) {
|
||
const c = characteristics[i];
|
||
if ((writeCharId == null || writeCharId == '') && c.properties != null && (c.properties.write || c.properties.writeWithoutResponse==true)) writeCharId = c.uuid;
|
||
if ((notifyCharId == null || notifyCharId == '') && c.properties != null && (c.properties.notify || c.properties.indicate)) notifyCharId = c.uuid;
|
||
}
|
||
if ((writeCharId == null || writeCharId == '') || (notifyCharId == null || notifyCharId == '')) throw new Error('未找到合适的写入或通知特征');
|
||
|
||
const deviceManager = DeviceManager.getInstance();
|
||
const device = deviceManager.getDevice(deviceId);
|
||
device!.serviceId = serviceId;
|
||
device!.writeCharId = writeCharId;
|
||
device!.notifyCharId = notifyCharId;
|
||
return { serviceId, writeCharId, notifyCharId };
|
||
}
|
||
async subscribeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, onData: BleDataReceivedCallback): Promise<void> {
|
||
return serviceManager.subscribeCharacteristic(deviceId, serviceId, characteristicId, onData);
|
||
}
|
||
async readCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<ArrayBuffer> {
|
||
return serviceManager.readCharacteristic(deviceId, serviceId, characteristicId);
|
||
}
|
||
async writeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, value: Uint8Array | ArrayBuffer, options?: WriteCharacteristicOptions): Promise<boolean> {
|
||
const payload = value instanceof Uint8Array ? value : new Uint8Array(value);
|
||
return serviceManager.writeCharacteristic(deviceId, serviceId, characteristicId, payload, options);
|
||
}
|
||
async unsubscribeCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<void> {
|
||
return serviceManager.unsubscribeCharacteristic(deviceId, serviceId, characteristicId);
|
||
}
|
||
async autoDiscoverAll(deviceId: string): Promise<any> {
|
||
return serviceManager.autoDiscoverAll(deviceId);
|
||
}
|
||
async subscribeAllNotifications(deviceId: string, onData: BleDataReceivedCallback): Promise<void> {
|
||
return serviceManager.subscribeAllNotifications(deviceId, onData);
|
||
}
|
||
}
|
||
|
||
const bluetoothServiceInstance = new BluetoothServiceShape();
|
||
BluetoothManager.setDefaultBluetoothService(bluetoothServiceInstance);
|
||
export const bluetoothService: BluetoothServiceContract = bluetoothServiceInstance;
|
||
export function getBluetoothService(): BluetoothServiceShape {
|
||
return bluetoothServiceInstance;
|
||
}
|
||
|
||
// Ensure protocol handlers are registered when this module is imported.
|
||
// import './protocol_registry.uts';
|