Files
akbleserver/uni_modules/ak-sbsrv/utssdk/protocol_handler.uts
2026-03-16 10:37:46 +08:00

116 lines
5.3 KiB
Plaintext

// Minimal ProtocolHandler runtime class used by pages and components.
// This class adapts the platform `BluetoothService` to a small protocol API
// expected by pages: setConnectionParameters, initialize, testBatteryLevel,
// testVersionInfo. Implemented conservatively to avoid heavy dependencies.
import type { BluetoothService, AutoBleInterfaces, AutoDiscoverAllResult, BleService, BleCharacteristic, BleProtocolType, BleDevice, ScanDevicesOptions, BleConnectOptionsExt, SendDataPayload, BleOptions } from './interface.uts'
export class ProtocolHandler {
// bluetoothService may be omitted for lightweight wrappers; allow null
bluetoothService: BluetoothService | null = null
protocol: BleProtocolType = 'standard'
deviceId: string | null = null
serviceId: string | null = null
writeCharId: string | null = null
notifyCharId: string | null = null
initialized: boolean = false
// Accept an optional BluetoothService so wrapper subclasses can call
// `super()` without forcing a runtime instance.
constructor(bluetoothService?: BluetoothService) {
if (bluetoothService != null) this.bluetoothService = bluetoothService
}
setConnectionParameters(deviceId: string, serviceId: string, writeCharId: string, notifyCharId: string) {
this.deviceId = deviceId
this.serviceId = serviceId
this.writeCharId = writeCharId
this.notifyCharId = notifyCharId
}
// initialize: optional setup, returns a Promise that resolves when ready
async initialize(): Promise<void> {
// Simple async initializer — keep implementation minimal and generator-friendly.
try {
// If bluetoothService exposes any protocol-specific setup, call it here.
this.initialized = true
return
} catch (e) {
throw e
}
}
// Protocol lifecycle / operations — default no-ops so generated code has
// concrete member references and platform-specific handlers can override.
async scanDevices(options?: ScanDevicesOptions): Promise<void> { return; }
async connect(device: BleDevice, options?: BleConnectOptionsExt): Promise<void> { return; }
async disconnect(device: BleDevice): Promise<void> { return; }
async sendData(device: BleDevice, payload?: SendDataPayload, options?: BleOptions): Promise<void> { return; }
async autoConnect(device: BleDevice, options?: BleConnectOptionsExt): Promise<AutoBleInterfaces> { return { serviceId: '', writeCharId: '', notifyCharId: '' }; }
// Example: testBatteryLevel will attempt to read the battery characteristic
// if write/notify-based protocol is not available. Returns number percentage.
async testBatteryLevel(): Promise<number> {
if (this.deviceId == null) throw new Error('deviceId not set')
// copy to local so Kotlin generator can smart-cast the value across awaits
const deviceId = this.deviceId
// try reading standard Battery characteristic (180F -> 2A19)
if (this.bluetoothService == null) throw new Error('bluetoothService not set')
const services = await this.bluetoothService.getServices(deviceId)
let found: BleService | null = null
for (let i = 0; i < services.length; i++) {
const s = services[i]
const uuidCandidate: string | null = (s != null && s.uuid != null ? s.uuid : null)
const uuid = uuidCandidate != null ? ('' + uuidCandidate).toLowerCase() : ''
if (uuid.indexOf('180f') !== -1) { found = s; break }
}
if (found == null) {
// fallback: if writeCharId exists and notify available use protocol (not implemented)
return 0
}
const foundUuid = found!.uuid
const charsRaw = await this.bluetoothService.getCharacteristics(deviceId, foundUuid)
const chars: BleCharacteristic[] = charsRaw
const batChar = chars.find((c: BleCharacteristic) => ((c.properties != null && c.properties.read) || (c.uuid != null && ('' + c.uuid).toLowerCase().includes('2a19'))))
if (batChar == null) return 0
const buf = await this.bluetoothService.readCharacteristic(deviceId, foundUuid, batChar.uuid)
const arr = new Uint8Array(buf)
if (arr.length > 0) {
return arr[0]
}
return 0
}
// testVersionInfo: try to read Device Information characteristics or return empty
async testVersionInfo(hw: boolean): Promise<string> {
// copy to local so Kotlin generator can smart-cast the value across awaits
const deviceId = this.deviceId
if (deviceId == null) return ''
// Device Information service 180A, characteristics: 2A26 (SW), 2A27 (HW) sometimes
if (this.bluetoothService == null) return ''
const _services = await this.bluetoothService.getServices(deviceId)
const services2: BleService[] = _services
let found2: BleService | null = null
for (let i = 0; i < services2.length; i++) {
const s = services2[i]
const uuidCandidate: string | null = (s != null && s.uuid != null ? s.uuid : null)
const uuid = uuidCandidate != null ? ('' + uuidCandidate).toLowerCase() : ''
if (uuid.indexOf('180a') !== -1) { found2 = s; break }
}
if (found2 == null) return ''
const _found2 = found2
const found2Uuid = _found2!.uuid
const chars = await this.bluetoothService.getCharacteristics(deviceId, found2Uuid)
const target = chars.find((c) => {
const id = ('' + c.uuid).toLowerCase()
if (hw) return id.includes('2a27') || id.includes('hardware')
return id.includes('2a26') || id.includes('software')
})
if (target == null) return ''
const buf = await this.bluetoothService.readCharacteristic(deviceId, found2Uuid, target.uuid)
try { return new TextDecoder().decode(new Uint8Array(buf)) } catch (e) { return '' }
}
}