import { type Channel, type DeviceCommand, type DeviceCommandResult, type DeviceState, type SensorState, type WaveFrame } from '@dg-kit/core'; import type { BluetoothDeviceLike, BluetoothRemoteGATTCharacteristicLike, BluetoothRemoteGATTServerLike } from './types.js'; export type StateListener = (state: DeviceState) => void; export interface WebBluetoothAvailability { supported: boolean; reason?: string; } export interface WebBluetoothConnectionContext { device: BluetoothDeviceLike; server: BluetoothRemoteGATTServerLike; } export interface WebBluetoothProtocolAdapter { onConnected(context: WebBluetoothConnectionContext): Promise; onDisconnected(): Promise; getState(): DeviceState; execute(command: DeviceCommand): Promise; emergencyStop(): Promise; subscribe(listener: StateListener): () => void; /** * Update the per-channel strength soft-limits. * * V3: re-sends a BF init packet so the device enforces the new limits. * V2: limits are clamped client-side at each tick (V2 protocol has no * device-side limit command). * * Limits also clamp current strength downward if reduced. */ setLimits(limitA: number, limitB: number): Promise; } /** * Contract for sensor-family devices (paw-prints, civet-edging): they push * event/telemetry streams instead of exposing a two-channel strength state, * so they get a narrower adapter shape than `WebBluetoothProtocolAdapter` * rather than being forced into the stim-specific `DeviceState`/ * `DeviceCommand` types. `TReading` is the device-specific parsed event * union (e.g. a button trigger, a pressure sample). */ export interface WebBluetoothSensorAdapter { onConnected(context: WebBluetoothConnectionContext): Promise; onDisconnected(): Promise; getState(): SensorState; /** Subscribe to parsed device readings/events. */ subscribe(listener: (reading: TReading) => void): () => void; onStateChanged(listener: (state: SensorState) => void): () => void; } export interface ChannelWaveState { waveformId?: string; frames: WaveFrame[] | null; index: number; loop: boolean; active: boolean; } export type Quad = [number, number, number, number]; export type WaveStep = { freq: number; int: number; }; export declare const INACTIVE_FREQ: Quad; export declare const INACTIVE_INT: Quad; export declare const SILENT_WAVE_STEP: WaveStep; export declare abstract class BaseCoyoteProtocolAdapter implements WebBluetoothProtocolAdapter { private readonly listeners; protected readonly waveState: Record; protected readonly burstRestores: Map; protected state: DeviceState; protected batteryChar: BluetoothRemoteGATTCharacteristicLike | null; private readonly tickLoop; private readonly waveCursor; protected tickPaused: boolean; protected suppressStaleStopStrengthNotifications: boolean; subscribe(listener: StateListener): () => void; onDisconnected(): Promise; protected resetConnectionState(options: { emit: boolean; }): Promise; getState(): DeviceState; execute(command: DeviceCommand): Promise; setLimits(limitA: number, limitB: number): Promise; emergencyStop(): Promise; protected setConnectedDevice(device: BluetoothDeviceLike): void; protected startProtocolLoop(): void; protected resetWaveState(): void; protected setWave(channel: Channel, waveformId: string, frames: WaveFrame[], loop: boolean): void; protected clearWave(channel: Channel): void; protected runBurst(channel: Channel, strength: number, durationMs: number): void; protected cancelBurstRestore(channel: Channel): void; protected onTick(): Promise; protected waitForTickIdle(): Promise; protected advanceWaveStep(channel: Channel): WaveStep | null; protected advanceWavePacket(channel: Channel): { freq: Quad; int: Quad; }; protected clamp(value: number, min: number, max: number): number; protected toInt(value: unknown, fallback?: number): number; protected readBattery(): Promise; protected shouldIgnoreStaleStopStrengthNotification(strengthA: number, strengthB: number): boolean; protected writeCharacteristicValue(characteristic: BluetoothRemoteGATTCharacteristicLike, value: ArrayBufferView | ArrayBuffer, options?: { preferResponse?: boolean; }): Promise; protected emit(): void; private startTickLoop; private stopTickLoop; protected abstract disconnectProtocol(): Promise; abstract onConnected(context: WebBluetoothConnectionContext): Promise; protected abstract resetProtocolState(): void; protected abstract resetEmergencyStopState(): void; protected abstract setAbsoluteStrength(channel: Channel, value: number): void; protected abstract adjustStrength(channel: Channel, delta: number): void; protected abstract performTick(): Promise; protected abstract writeEmergencyStopPacket(): Promise; /** * Push the current `state.limitA` / `state.limitB` to the device. * V3 sends a BF packet; V2 is a no-op (limits enforced via clamp at tick). */ protected abstract writeLimitsToDevice(): Promise; } //# sourceMappingURL=base.d.ts.map