@dg-kit/protocol 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base.d.ts +17 -1
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +2 -24
- package/dist/base.js.map +1 -1
- package/dist/civet-edging.d.ts +61 -0
- package/dist/civet-edging.d.ts.map +1 -0
- package/dist/civet-edging.js +152 -0
- package/dist/civet-edging.js.map +1 -0
- package/dist/constants.d.ts +24 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +62 -0
- package/dist/constants.js.map +1 -1
- package/dist/facade.d.ts +14 -2
- package/dist/facade.d.ts.map +1 -1
- package/dist/facade.js +21 -3
- package/dist/facade.js.map +1 -1
- package/dist/gatt-utils.d.ts +42 -0
- package/dist/gatt-utils.d.ts.map +1 -0
- package/dist/gatt-utils.js +99 -0
- package/dist/gatt-utils.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/opossum.d.ts +99 -0
- package/dist/opossum.d.ts.map +1 -0
- package/dist/opossum.js +238 -0
- package/dist/opossum.js.map +1 -0
- package/dist/paw-prints.d.ts +78 -0
- package/dist/paw-prints.d.ts.map +1 -0
- package/dist/paw-prints.js +243 -0
- package/dist/paw-prints.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/v3.d.ts.map +1 -1
- package/dist/v3.js +2 -0
- package/dist/v3.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { BluetoothRemoteGATTCharacteristicLike, BluetoothRemoteGATTServerLike } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Shared GATT write with a fallback chain across the three write methods a
|
|
4
|
+
* characteristic might expose. Standalone (not a class method) so every
|
|
5
|
+
* 47L12x-family adapter can call it without needing to extend
|
|
6
|
+
* `BaseCoyoteProtocolAdapter` — Coyote, paw-prints, civet-edging, and
|
|
7
|
+
* opossum all share this exact write behavior even though their command
|
|
8
|
+
* shapes differ.
|
|
9
|
+
*/
|
|
10
|
+
export declare function writeCharacteristicValue(characteristic: BluetoothRemoteGATTCharacteristicLike, value: ArrayBufferView | ArrayBuffer, options?: {
|
|
11
|
+
preferResponse?: boolean;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Newer firmware (flashed via the official app) ignores normal control
|
|
15
|
+
* writes on the 0x180C/0x150A characteristic until it has seen the same
|
|
16
|
+
* connect-time sequence the app always sends: an init packet, best-effort
|
|
17
|
+
* subscription to two legacy/OTA notify channels, and an MTU bump to 140.
|
|
18
|
+
*
|
|
19
|
+
* The official app sends this exact same init packet unconditionally to
|
|
20
|
+
* every 47L12x-family device it connects to — Coyote, paw-prints,
|
|
21
|
+
* civet-edging, and opossum all share the identical 0x180C GATT skeleton —
|
|
22
|
+
* old and new firmware alike, with no firmware-version detection gating it.
|
|
23
|
+
* So this needs to run for all four device adapters, not just Coyote V3;
|
|
24
|
+
* originally it only ran there, which reproduced the exact "device won't
|
|
25
|
+
* respond" symptom for the three newer device kinds. Every step is
|
|
26
|
+
* best-effort/non-fatal, including the init write itself: if any step fails
|
|
27
|
+
* on a real device this hasn't been tested against, the caller's normal
|
|
28
|
+
* control writes still proceed rather than the connection being refused.
|
|
29
|
+
*/
|
|
30
|
+
export declare function performV3FamilyConnectHandshake(server: BluetoothRemoteGATTServerLike, writeChar: BluetoothRemoteGATTCharacteristicLike): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* The 47L12x-family indicator LED is a discrete 8-color enum, not a
|
|
33
|
+
* continuous byte — confirmed against the community protocol doc's
|
|
34
|
+
* paw-prints color table (0=熄灭/off, 1=黄, 2=红, 3=紫, 4=蓝, 5=青, 6=绿,
|
|
35
|
+
* 7=白) and consistent with civet-edging's one documented example
|
|
36
|
+
* ("01为黄色" — matches index 1 in that same table). Values 8-255 have no
|
|
37
|
+
* defined meaning on real hardware, so every adapter clamps here rather
|
|
38
|
+
* than trusting the caller (a stray remote-control byte or a naive 0-255
|
|
39
|
+
* color picker would otherwise reach the wire unclamped).
|
|
40
|
+
*/
|
|
41
|
+
export declare function clampIndicatorColor(color: number): number;
|
|
42
|
+
//# sourceMappingURL=gatt-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gatt-utils.d.ts","sourceRoot":"","sources":["../src/gatt-utils.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qCAAqC,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAEvG;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC5C,cAAc,EAAE,qCAAqC,EACrD,KAAK,EAAE,eAAe,GAAG,WAAW,EACpC,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACzC,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,6BAA6B,EACrC,SAAS,EAAE,qCAAqC,GAC/C,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { V3_HANDSHAKE_MTU, V3_INIT_PACKET, V3_LEGACY_NOTIFY_CHAR, V3_LEGACY_SERVICE, V3_NORDIC_OTA_CHAR, V3_NORDIC_OTA_SERVICE, } from './constants.js';
|
|
2
|
+
/**
|
|
3
|
+
* Shared GATT write with a fallback chain across the three write methods a
|
|
4
|
+
* characteristic might expose. Standalone (not a class method) so every
|
|
5
|
+
* 47L12x-family adapter can call it without needing to extend
|
|
6
|
+
* `BaseCoyoteProtocolAdapter` — Coyote, paw-prints, civet-edging, and
|
|
7
|
+
* opossum all share this exact write behavior even though their command
|
|
8
|
+
* shapes differ.
|
|
9
|
+
*/
|
|
10
|
+
export async function writeCharacteristicValue(characteristic, value, options = {}) {
|
|
11
|
+
const attempts = options.preferResponse
|
|
12
|
+
? [
|
|
13
|
+
characteristic.writeValueWithResponse?.bind(characteristic),
|
|
14
|
+
characteristic.writeValueWithoutResponse?.bind(characteristic),
|
|
15
|
+
characteristic.writeValue?.bind(characteristic),
|
|
16
|
+
]
|
|
17
|
+
: [
|
|
18
|
+
characteristic.writeValueWithoutResponse?.bind(characteristic),
|
|
19
|
+
characteristic.writeValueWithResponse?.bind(characteristic),
|
|
20
|
+
characteristic.writeValue?.bind(characteristic),
|
|
21
|
+
];
|
|
22
|
+
let lastError = null;
|
|
23
|
+
for (const attempt of attempts) {
|
|
24
|
+
if (!attempt)
|
|
25
|
+
continue;
|
|
26
|
+
try {
|
|
27
|
+
await attempt(value);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
lastError = error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
throw lastError ?? new Error('Bluetooth characteristic is not writable');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Newer firmware (flashed via the official app) ignores normal control
|
|
38
|
+
* writes on the 0x180C/0x150A characteristic until it has seen the same
|
|
39
|
+
* connect-time sequence the app always sends: an init packet, best-effort
|
|
40
|
+
* subscription to two legacy/OTA notify channels, and an MTU bump to 140.
|
|
41
|
+
*
|
|
42
|
+
* The official app sends this exact same init packet unconditionally to
|
|
43
|
+
* every 47L12x-family device it connects to — Coyote, paw-prints,
|
|
44
|
+
* civet-edging, and opossum all share the identical 0x180C GATT skeleton —
|
|
45
|
+
* old and new firmware alike, with no firmware-version detection gating it.
|
|
46
|
+
* So this needs to run for all four device adapters, not just Coyote V3;
|
|
47
|
+
* originally it only ran there, which reproduced the exact "device won't
|
|
48
|
+
* respond" symptom for the three newer device kinds. Every step is
|
|
49
|
+
* best-effort/non-fatal, including the init write itself: if any step fails
|
|
50
|
+
* on a real device this hasn't been tested against, the caller's normal
|
|
51
|
+
* control writes still proceed rather than the connection being refused.
|
|
52
|
+
*/
|
|
53
|
+
export async function performV3FamilyConnectHandshake(server, writeChar) {
|
|
54
|
+
try {
|
|
55
|
+
await writeCharacteristicValue(writeChar, V3_INIT_PACKET);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Best-effort — see function comment above.
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const legacyService = await server.getPrimaryService(V3_LEGACY_SERVICE);
|
|
62
|
+
const legacyChar = await legacyService.getCharacteristic(V3_LEGACY_NOTIFY_CHAR);
|
|
63
|
+
await legacyChar.startNotifications();
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Not present on this firmware/hardware — non-fatal.
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const otaService = await server.getPrimaryService(V3_NORDIC_OTA_SERVICE);
|
|
70
|
+
const otaChar = await otaService.getCharacteristic(V3_NORDIC_OTA_CHAR);
|
|
71
|
+
await otaChar.startNotifications();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Only present on OTA-capable firmware — non-fatal.
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
await server.requestMTU?.(V3_HANDSHAKE_MTU);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Transport may not support MTU negotiation — non-fatal.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The 47L12x-family indicator LED is a discrete 8-color enum, not a
|
|
85
|
+
* continuous byte — confirmed against the community protocol doc's
|
|
86
|
+
* paw-prints color table (0=熄灭/off, 1=黄, 2=红, 3=紫, 4=蓝, 5=青, 6=绿,
|
|
87
|
+
* 7=白) and consistent with civet-edging's one documented example
|
|
88
|
+
* ("01为黄色" — matches index 1 in that same table). Values 8-255 have no
|
|
89
|
+
* defined meaning on real hardware, so every adapter clamps here rather
|
|
90
|
+
* than trusting the caller (a stray remote-control byte or a naive 0-255
|
|
91
|
+
* color picker would otherwise reach the wire unclamped).
|
|
92
|
+
*/
|
|
93
|
+
export function clampIndicatorColor(color) {
|
|
94
|
+
const value = Number(color);
|
|
95
|
+
if (!Number.isFinite(value))
|
|
96
|
+
return 0;
|
|
97
|
+
return Math.max(0, Math.min(7, Math.round(value)));
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=gatt-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gatt-utils.js","sourceRoot":"","sources":["../src/gatt-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAGxB;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,cAAqD,EACrD,KAAoC,EACpC,UAAwC,EAAE;IAE1C,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc;QACrC,CAAC,CAAC;YACE,cAAc,CAAC,sBAAsB,EAAE,IAAI,CAAC,cAAc,CAAC;YAC3D,cAAc,CAAC,yBAAyB,EAAE,IAAI,CAAC,cAAc,CAAC;YAC9D,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC;SAChD;QACH,CAAC,CAAC;YACE,cAAc,CAAC,yBAAyB,EAAE,IAAI,CAAC,cAAc,CAAC;YAC9D,cAAc,CAAC,sBAAsB,EAAE,IAAI,CAAC,cAAc,CAAC;YAC3D,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC;SAChD,CAAC;IAEN,IAAI,SAAS,GAAY,IAAI,CAAC;IAC9B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAC;QACpB,CAAC;IACH,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,MAAqC,EACrC,SAAgD;IAEhD,IAAI,CAAC;QACH,MAAM,wBAAwB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;IAC9C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;QACxE,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,CAAC;QAChF,MAAM,UAAU,CAAC,kBAAkB,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,qDAAqD;IACvD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,CAAC;QACzE,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;QACvE,MAAM,OAAO,CAAC,kBAAkB,EAAE,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,oDAAoD;IACtD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;IAC3D,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export * from './constants.js';
|
|
2
2
|
export * from './types.js';
|
|
3
|
-
export { BaseCoyoteProtocolAdapter, INACTIVE_FREQ, INACTIVE_INT, SILENT_WAVE_STEP, type ChannelWaveState, type Quad, type StateListener, type WaveStep, type WebBluetoothAvailability, type WebBluetoothConnectionContext, type WebBluetoothProtocolAdapter, } from './base.js';
|
|
3
|
+
export { BaseCoyoteProtocolAdapter, INACTIVE_FREQ, INACTIVE_INT, SILENT_WAVE_STEP, type ChannelWaveState, type Quad, type StateListener, type WaveStep, type WebBluetoothAvailability, type WebBluetoothConnectionContext, type WebBluetoothProtocolAdapter, type WebBluetoothSensorAdapter, } from './base.js';
|
|
4
4
|
export { CoyoteV2ProtocolAdapter } from './v2.js';
|
|
5
5
|
export { CoyoteV3ProtocolAdapter } from './v3.js';
|
|
6
6
|
export { CoyoteProtocolAdapter } from './facade.js';
|
|
7
|
+
export { PawPrintsSensorAdapter, type PawPrintsReading, type PawPrintsReadingListener, type PawPrintsStateListener, } from './paw-prints.js';
|
|
8
|
+
export { CivetPressureSensorAdapter, type CivetPressureReading } from './civet-edging.js';
|
|
9
|
+
export { OpossumVibrateAdapter, createEmptyOpossumState, type OpossumState, type OpossumButton, type OpossumButtonEvent, } from './opossum.js';
|
|
7
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,4 +4,7 @@ export { BaseCoyoteProtocolAdapter, INACTIVE_FREQ, INACTIVE_INT, SILENT_WAVE_STE
|
|
|
4
4
|
export { CoyoteV2ProtocolAdapter } from './v2.js';
|
|
5
5
|
export { CoyoteV3ProtocolAdapter } from './v3.js';
|
|
6
6
|
export { CoyoteProtocolAdapter } from './facade.js';
|
|
7
|
+
export { PawPrintsSensorAdapter, } from './paw-prints.js';
|
|
8
|
+
export { CivetPressureSensorAdapter } from './civet-edging.js';
|
|
9
|
+
export { OpossumVibrateAdapter, createEmptyOpossumState, } from './opossum.js';
|
|
7
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,YAAY,EACZ,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,YAAY,EACZ,gBAAgB,GASjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,sBAAsB,GAIvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAA6B,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GAIxB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opossum Vibrate Controller (负鼠振动控制器) protocol adapter.
|
|
3
|
+
*
|
|
4
|
+
* Unlike Coyote (stim, strength+waveform) or the paw-prints/civet-edging
|
|
5
|
+
* sensors (pure telemetry), this is a dual-channel vibration device that
|
|
6
|
+
* both accepts intensity commands (output) AND reports physical button
|
|
7
|
+
* presses (input). It doesn't fit `WebBluetoothProtocolAdapter` (that
|
|
8
|
+
* interface's `DeviceCommand`/`DeviceState` are Coyote-strength-shaped with
|
|
9
|
+
* frequency/waveform concepts this device has no notion of) or
|
|
10
|
+
* `WebBluetoothSensorAdapter` (this device isn't pure-sensor), so it gets
|
|
11
|
+
* its own standalone public API instead.
|
|
12
|
+
*
|
|
13
|
+
* GATT skeleton is identical to Coyote V3 (service 0x180C, write 0x150A,
|
|
14
|
+
* notify 0x150B, battery 0x180A/0x1500) — only the opcodes differ.
|
|
15
|
+
*
|
|
16
|
+
* Assumption: the community protocol doc's marketing name "Opossum
|
|
17
|
+
* Vibration Controller 47L127000" suggests a product-name-prefixed BLE
|
|
18
|
+
* name, but every sibling 47L12x-family device advertises a bare
|
|
19
|
+
* `47L1XX000`-style model string with no product-name prefix, so the
|
|
20
|
+
* advertised BLE name is assumed to be just `47L127000`
|
|
21
|
+
* (`OPOSSUM_DEVICE_NAME_PREFIX`), not literally starting with "Opossum".
|
|
22
|
+
*
|
|
23
|
+
* Android side note from the doc: MTU should be negotiated up to 144 for
|
|
24
|
+
* this device family. That's a transport-layer concern (the caller's BLE
|
|
25
|
+
* connect step), out of scope here — this file only builds/parses packets.
|
|
26
|
+
*/
|
|
27
|
+
import type { Channel } from '@dg-kit/core';
|
|
28
|
+
import type { WebBluetoothConnectionContext } from './base.js';
|
|
29
|
+
export interface OpossumState {
|
|
30
|
+
connected: boolean;
|
|
31
|
+
deviceName?: string;
|
|
32
|
+
address?: string;
|
|
33
|
+
battery?: number;
|
|
34
|
+
intensityA: number;
|
|
35
|
+
intensityB: number;
|
|
36
|
+
}
|
|
37
|
+
export declare function createEmptyOpossumState(): OpossumState;
|
|
38
|
+
export type OpossumButton = 'SEL_1' | 'SEL_2' | 'HOME' | 'Up' | 'Down' | 'Left' | 'Right' | 'B' | 'A' | 'G' | 'D';
|
|
39
|
+
export interface OpossumButtonEvent {
|
|
40
|
+
sequence: number;
|
|
41
|
+
pressed: Set<OpossumButton>;
|
|
42
|
+
}
|
|
43
|
+
type OpossumStateListener = (state: OpossumState) => void;
|
|
44
|
+
type OpossumButtonListener = (event: OpossumButtonEvent) => void;
|
|
45
|
+
export declare class OpossumVibrateAdapter {
|
|
46
|
+
private state;
|
|
47
|
+
private writeChar;
|
|
48
|
+
private notifyChar;
|
|
49
|
+
private batteryChar;
|
|
50
|
+
private readonly stateListeners;
|
|
51
|
+
private readonly buttonListeners;
|
|
52
|
+
onConnected(context: WebBluetoothConnectionContext): Promise<void>;
|
|
53
|
+
onDisconnected(): Promise<void>;
|
|
54
|
+
getState(): OpossumState;
|
|
55
|
+
subscribeButtons(listener: OpossumButtonListener): () => void;
|
|
56
|
+
onStateChanged(listener: OpossumStateListener): () => void;
|
|
57
|
+
/**
|
|
58
|
+
* 0xB3 direct intensity: A/B in 0-200, or 'unchanged' to leave that
|
|
59
|
+
* channel as-is (mapped to the 0xFF sentinel byte).
|
|
60
|
+
*/
|
|
61
|
+
setIntensity(channelA: number | 'unchanged', channelB: number | 'unchanged'): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Relative adjust for one channel, e.g. for a `vibrate_adjust` tool call.
|
|
64
|
+
* Reads the current intensity and writes the new absolute value in one
|
|
65
|
+
* call so a caller never has to do `getState()` + `setIntensity()` as two
|
|
66
|
+
* separate steps — doing it as two steps would let two concurrent adjust
|
|
67
|
+
* calls (an LLM tool call racing a manual UI tweak, say) both read the
|
|
68
|
+
* same stale value and the second write silently clobber the first's
|
|
69
|
+
* delta instead of compounding.
|
|
70
|
+
*/
|
|
71
|
+
adjustIntensity(channel: Channel, delta: number): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* 0xB0 vibration waveform. This is a single packet builder/writer — the
|
|
74
|
+
* device expects it re-sent (~every 100ms) by the CALLER to sustain a
|
|
75
|
+
* waveform effect, but that re-send loop is the caller's responsibility;
|
|
76
|
+
* this device doesn't need (and this adapter doesn't run) a tick loop
|
|
77
|
+
* the way Coyote does, since 0xB3 is a direct "set now" command.
|
|
78
|
+
*/
|
|
79
|
+
writeWaveformFrame(channelA: [number, number, number, number], channelB: [number, number, number, number]): Promise<void>;
|
|
80
|
+
/** 0x50 LED color + button-state-reporting toggle. */
|
|
81
|
+
setLed(color: number, enableButtonReporting: boolean): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* 0xB2 screen display update: fixed 21-byte preamble + current A/B
|
|
84
|
+
* intensity. The source doc's summary states "23 bytes" total but also
|
|
85
|
+
* enumerates exactly 21 fixed preamble bytes; 1 (opcode) + 21 + 2 (A/B)
|
|
86
|
+
* is actually 24. Trusting the literal, unambiguous byte enumeration over
|
|
87
|
+
* the (likely miscounted) total-length label.
|
|
88
|
+
*/
|
|
89
|
+
updateDisplay(channelA: number, channelB: number): Promise<void>;
|
|
90
|
+
/** Best-effort safety call: drive both channels to zero, ignore failures. */
|
|
91
|
+
emergencyStop(): Promise<void>;
|
|
92
|
+
private readonly handleNotification;
|
|
93
|
+
private write;
|
|
94
|
+
private clamp;
|
|
95
|
+
private emitState;
|
|
96
|
+
private emitButtonEvent;
|
|
97
|
+
}
|
|
98
|
+
export {};
|
|
99
|
+
//# sourceMappingURL=opossum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opossum.d.ts","sourceRoot":"","sources":["../src/opossum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAe/D,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,uBAAuB,IAAI,YAAY,CAEtD;AAED,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,OAAO,GACP,MAAM,GACN,IAAI,GACJ,MAAM,GACN,MAAM,GACN,OAAO,GACP,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,CAAC;AAER,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;CAC7B;AAiBD,KAAK,oBAAoB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAC1D,KAAK,qBAAqB,GAAG,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAEjE,qBAAa,qBAAqB;IAChC,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,SAAS,CAAsD;IACvE,OAAO,CAAC,UAAU,CAAsD;IACxE,OAAO,CAAC,WAAW,CAAsD;IAEzE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmC;IAClE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoC;IAE9D,WAAW,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC;IA0ClE,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBrC,QAAQ,IAAI,YAAY;IAIxB,gBAAgB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,IAAI;IAO7D,cAAc,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAO1D;;;OAGG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,GAAG,WAAW,EAC9B,QAAQ,EAAE,MAAM,GAAG,WAAW,GAC7B,OAAO,CAAC,IAAI,CAAC;IAYhB;;;;;;;;OAQG;IACG,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrE;;;;;;OAMG;IACG,kBAAkB,CACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAC1C,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACzC,OAAO,CAAC,IAAI,CAAC;IAchB,sDAAsD;IAChD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1E;;;;;;OAMG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IActE,6EAA6E;IACvE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAwBjC;YAEY,KAAK;IAOnB,OAAO,CAAC,KAAK;IAMb,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,eAAe;CAKxB"}
|
package/dist/opossum.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { V3_BATTERY_CHAR, V3_BATTERY_SERVICE, V3_NOTIFY_CHAR, V3_PRIMARY_SERVICE, V3_WRITE_CHAR, } from './constants.js';
|
|
2
|
+
import { clampIndicatorColor, performV3FamilyConnectHandshake, writeCharacteristicValue, } from './gatt-utils.js';
|
|
3
|
+
export function createEmptyOpossumState() {
|
|
4
|
+
return { connected: false, battery: 0, intensityA: 0, intensityB: 0 };
|
|
5
|
+
}
|
|
6
|
+
/** Bit position (in the little-endian 16-bit bitmap) for each named button. */
|
|
7
|
+
const BUTTON_BITS = [
|
|
8
|
+
['SEL_1', 0],
|
|
9
|
+
['SEL_2', 1],
|
|
10
|
+
['HOME', 2],
|
|
11
|
+
['Up', 8],
|
|
12
|
+
['Down', 9],
|
|
13
|
+
['Left', 10],
|
|
14
|
+
['Right', 11],
|
|
15
|
+
['B', 12],
|
|
16
|
+
['A', 13],
|
|
17
|
+
['G', 14],
|
|
18
|
+
['D', 15],
|
|
19
|
+
];
|
|
20
|
+
export class OpossumVibrateAdapter {
|
|
21
|
+
state = createEmptyOpossumState();
|
|
22
|
+
writeChar = null;
|
|
23
|
+
notifyChar = null;
|
|
24
|
+
batteryChar = null;
|
|
25
|
+
stateListeners = new Set();
|
|
26
|
+
buttonListeners = new Set();
|
|
27
|
+
async onConnected(context) {
|
|
28
|
+
try {
|
|
29
|
+
const primaryService = await context.server.getPrimaryService(V3_PRIMARY_SERVICE);
|
|
30
|
+
this.writeChar = await primaryService.getCharacteristic(V3_WRITE_CHAR);
|
|
31
|
+
this.notifyChar = await primaryService.getCharacteristic(V3_NOTIFY_CHAR);
|
|
32
|
+
await this.notifyChar.startNotifications();
|
|
33
|
+
this.notifyChar.addEventListener('characteristicvaluechanged', this.handleNotification);
|
|
34
|
+
await performV3FamilyConnectHandshake(context.server, this.writeChar);
|
|
35
|
+
let battery = 0;
|
|
36
|
+
try {
|
|
37
|
+
const batteryService = await context.server.getPrimaryService(V3_BATTERY_SERVICE);
|
|
38
|
+
this.batteryChar = await batteryService.getCharacteristic(V3_BATTERY_CHAR);
|
|
39
|
+
const value = await this.batteryChar.readValue();
|
|
40
|
+
battery = value.getUint8(0);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Best-effort: some units don't expose (or fail to read) battery.
|
|
44
|
+
this.batteryChar = null;
|
|
45
|
+
battery = 0;
|
|
46
|
+
}
|
|
47
|
+
this.state = {
|
|
48
|
+
connected: true,
|
|
49
|
+
deviceName: context.device.name ?? '',
|
|
50
|
+
address: context.device.id ?? '',
|
|
51
|
+
battery,
|
|
52
|
+
intensityA: 0,
|
|
53
|
+
intensityB: 0,
|
|
54
|
+
};
|
|
55
|
+
this.emitState();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
// Tear down the same way onDisconnected() does — if startNotifications()
|
|
59
|
+
// and addEventListener() above already succeeded before a later step
|
|
60
|
+
// threw (e.g. the handshake or battery read), leaving the subscription
|
|
61
|
+
// live here would leak it silently, since nothing else will ever call
|
|
62
|
+
// stopNotifications()/removeEventListener() for this failed attempt.
|
|
63
|
+
await this.onDisconnected();
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async onDisconnected() {
|
|
68
|
+
if (this.notifyChar) {
|
|
69
|
+
this.notifyChar.removeEventListener('characteristicvaluechanged', this.handleNotification);
|
|
70
|
+
try {
|
|
71
|
+
await this.notifyChar.stopNotifications();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// ignore best effort
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
this.writeChar = null;
|
|
78
|
+
this.notifyChar = null;
|
|
79
|
+
this.batteryChar = null;
|
|
80
|
+
this.state = createEmptyOpossumState();
|
|
81
|
+
this.emitState();
|
|
82
|
+
}
|
|
83
|
+
getState() {
|
|
84
|
+
return { ...this.state };
|
|
85
|
+
}
|
|
86
|
+
subscribeButtons(listener) {
|
|
87
|
+
this.buttonListeners.add(listener);
|
|
88
|
+
return () => {
|
|
89
|
+
this.buttonListeners.delete(listener);
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
onStateChanged(listener) {
|
|
93
|
+
this.stateListeners.add(listener);
|
|
94
|
+
return () => {
|
|
95
|
+
this.stateListeners.delete(listener);
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 0xB3 direct intensity: A/B in 0-200, or 'unchanged' to leave that
|
|
100
|
+
* channel as-is (mapped to the 0xFF sentinel byte).
|
|
101
|
+
*/
|
|
102
|
+
async setIntensity(channelA, channelB) {
|
|
103
|
+
const byteA = channelA === 'unchanged' ? 0xff : this.clamp(channelA, 0, 200);
|
|
104
|
+
const byteB = channelB === 'unchanged' ? 0xff : this.clamp(channelB, 0, 200);
|
|
105
|
+
const packet = new Uint8Array([0xb3, byteA, byteB]);
|
|
106
|
+
await this.write(packet);
|
|
107
|
+
if (channelA !== 'unchanged')
|
|
108
|
+
this.state.intensityA = byteA;
|
|
109
|
+
if (channelB !== 'unchanged')
|
|
110
|
+
this.state.intensityB = byteB;
|
|
111
|
+
this.emitState();
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Relative adjust for one channel, e.g. for a `vibrate_adjust` tool call.
|
|
115
|
+
* Reads the current intensity and writes the new absolute value in one
|
|
116
|
+
* call so a caller never has to do `getState()` + `setIntensity()` as two
|
|
117
|
+
* separate steps — doing it as two steps would let two concurrent adjust
|
|
118
|
+
* calls (an LLM tool call racing a manual UI tweak, say) both read the
|
|
119
|
+
* same stale value and the second write silently clobber the first's
|
|
120
|
+
* delta instead of compounding.
|
|
121
|
+
*/
|
|
122
|
+
async adjustIntensity(channel, delta) {
|
|
123
|
+
const current = channel === 'A' ? this.state.intensityA : this.state.intensityB;
|
|
124
|
+
const next = this.clamp(current + delta, 0, 200);
|
|
125
|
+
if (channel === 'A') {
|
|
126
|
+
await this.setIntensity(next, 'unchanged');
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
await this.setIntensity('unchanged', next);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 0xB0 vibration waveform. This is a single packet builder/writer — the
|
|
134
|
+
* device expects it re-sent (~every 100ms) by the CALLER to sustain a
|
|
135
|
+
* waveform effect, but that re-send loop is the caller's responsibility;
|
|
136
|
+
* this device doesn't need (and this adapter doesn't run) a tick loop
|
|
137
|
+
* the way Coyote does, since 0xB3 is a direct "set now" command.
|
|
138
|
+
*/
|
|
139
|
+
async writeWaveformFrame(channelA, channelB) {
|
|
140
|
+
const packet = new Uint8Array(20);
|
|
141
|
+
packet[0] = 0xb0;
|
|
142
|
+
// bytes 1-7 are reserved/zero
|
|
143
|
+
for (let i = 0; i < 4; i++) {
|
|
144
|
+
// Doc doesn't fully specify "invalidates" semantics for >100 bytes;
|
|
145
|
+
// clamping to 100 is the conservative reading rather than wrapping.
|
|
146
|
+
packet[8 + i] = this.clamp(channelA[i] ?? 0, 0, 100);
|
|
147
|
+
packet[16 + i] = this.clamp(channelB[i] ?? 0, 0, 100);
|
|
148
|
+
}
|
|
149
|
+
// bytes 12-15 are reserved/zero
|
|
150
|
+
await this.write(packet);
|
|
151
|
+
}
|
|
152
|
+
/** 0x50 LED color + button-state-reporting toggle. */
|
|
153
|
+
async setLed(color, enableButtonReporting) {
|
|
154
|
+
const packet = new Uint8Array([
|
|
155
|
+
0x50,
|
|
156
|
+
clampIndicatorColor(color),
|
|
157
|
+
enableButtonReporting ? 0x01 : 0x00,
|
|
158
|
+
]);
|
|
159
|
+
await this.write(packet);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 0xB2 screen display update: fixed 21-byte preamble + current A/B
|
|
163
|
+
* intensity. The source doc's summary states "23 bytes" total but also
|
|
164
|
+
* enumerates exactly 21 fixed preamble bytes; 1 (opcode) + 21 + 2 (A/B)
|
|
165
|
+
* is actually 24. Trusting the literal, unambiguous byte enumeration over
|
|
166
|
+
* the (likely miscounted) total-length label.
|
|
167
|
+
*/
|
|
168
|
+
async updateDisplay(channelA, channelB) {
|
|
169
|
+
const preamble = [
|
|
170
|
+
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
171
|
+
0xff, 0xff, 0xff, 0xff, 0x08, 0x09,
|
|
172
|
+
];
|
|
173
|
+
const packet = new Uint8Array([
|
|
174
|
+
0xb2,
|
|
175
|
+
...preamble,
|
|
176
|
+
this.clamp(channelA, 0, 200),
|
|
177
|
+
this.clamp(channelB, 0, 200),
|
|
178
|
+
]);
|
|
179
|
+
await this.write(packet);
|
|
180
|
+
}
|
|
181
|
+
/** Best-effort safety call: drive both channels to zero, ignore failures. */
|
|
182
|
+
async emergencyStop() {
|
|
183
|
+
try {
|
|
184
|
+
await this.setIntensity(0, 0);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// ignore best effort
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
handleNotification = (event) => {
|
|
191
|
+
const target = event.target;
|
|
192
|
+
const value = target?.value;
|
|
193
|
+
if (!value || value.byteLength < 1)
|
|
194
|
+
return;
|
|
195
|
+
const opcode = value.getUint8(0);
|
|
196
|
+
if (opcode === 0xb3 && value.byteLength >= 3) {
|
|
197
|
+
this.state.intensityA = value.getUint8(1);
|
|
198
|
+
this.state.intensityB = value.getUint8(2);
|
|
199
|
+
this.emitState();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (opcode === 0xd0 && value.byteLength >= 4) {
|
|
203
|
+
const sequence = value.getUint8(1);
|
|
204
|
+
const bitmap = value.getUint8(2) | (value.getUint8(3) << 8);
|
|
205
|
+
const pressed = new Set();
|
|
206
|
+
for (const [button, bit] of BUTTON_BITS) {
|
|
207
|
+
if ((bitmap & (1 << bit)) !== 0) {
|
|
208
|
+
pressed.add(button);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
this.emitButtonEvent({ sequence, pressed });
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
async write(packet) {
|
|
215
|
+
if (!this.writeChar) {
|
|
216
|
+
throw new Error('Opossum device is not connected');
|
|
217
|
+
}
|
|
218
|
+
await writeCharacteristicValue(this.writeChar, packet);
|
|
219
|
+
}
|
|
220
|
+
clamp(value, min, max) {
|
|
221
|
+
const number = Number(value);
|
|
222
|
+
if (!Number.isFinite(number))
|
|
223
|
+
return min;
|
|
224
|
+
return Math.max(min, Math.min(max, Math.round(number)));
|
|
225
|
+
}
|
|
226
|
+
emitState() {
|
|
227
|
+
const snapshot = this.getState();
|
|
228
|
+
for (const listener of this.stateListeners) {
|
|
229
|
+
listener(snapshot);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
emitButtonEvent(event) {
|
|
233
|
+
for (const listener of this.buttonListeners) {
|
|
234
|
+
listener(event);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=opossum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opossum.js","sourceRoot":"","sources":["../src/opossum.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol adapter for the "Paw-Prints" (爪印) wireless button/motion sensor.
|
|
3
|
+
*
|
|
4
|
+
* Shares the exact GATT skeleton with Coyote V3 (service 0x180C, write
|
|
5
|
+
* 0x150A, notify 0x150B, battery 0x180A/0x1500) — only the application-layer
|
|
6
|
+
* opcodes differ, so the transport wiring below mirrors `v3.ts` but the
|
|
7
|
+
* command/notification framing is Paw-Prints-specific.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: the byte layout below is transcribed from a paraphrased summary of
|
|
10
|
+
* the community protocol doc, not a byte-exact spec or a real device
|
|
11
|
+
* capture. Fields called out with a comment are best-effort interpretations
|
|
12
|
+
* that need confirming against real hardware before being treated as
|
|
13
|
+
* authoritative.
|
|
14
|
+
*/
|
|
15
|
+
import { type SensorState } from '@dg-kit/core';
|
|
16
|
+
import type { WebBluetoothConnectionContext, WebBluetoothSensorAdapter } from './base.js';
|
|
17
|
+
export type PawPrintsReading = {
|
|
18
|
+
type: 'status';
|
|
19
|
+
color: number;
|
|
20
|
+
deviceType: number;
|
|
21
|
+
battery: number;
|
|
22
|
+
} | {
|
|
23
|
+
type: 'trigger';
|
|
24
|
+
eventId: number;
|
|
25
|
+
parameterValue: number;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'triggerCancel';
|
|
28
|
+
eventId: number;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'parameterChange';
|
|
31
|
+
eventId: number;
|
|
32
|
+
value: number;
|
|
33
|
+
} | {
|
|
34
|
+
type: 'physical';
|
|
35
|
+
sequence: number;
|
|
36
|
+
pressState: number;
|
|
37
|
+
acceleration: number;
|
|
38
|
+
angleX: number;
|
|
39
|
+
angleY: number;
|
|
40
|
+
angleZ: number;
|
|
41
|
+
extVoltage: number;
|
|
42
|
+
} | {
|
|
43
|
+
type: 'autoDetectResult';
|
|
44
|
+
xRange: [number, number];
|
|
45
|
+
yRange: [number, number];
|
|
46
|
+
zRange: [number, number];
|
|
47
|
+
};
|
|
48
|
+
export type PawPrintsReadingListener = (reading: PawPrintsReading) => void;
|
|
49
|
+
export type PawPrintsStateListener = (state: SensorState) => void;
|
|
50
|
+
export declare class PawPrintsSensorAdapter implements WebBluetoothSensorAdapter<PawPrintsReading> {
|
|
51
|
+
private state;
|
|
52
|
+
private writeChar;
|
|
53
|
+
private notifyChar;
|
|
54
|
+
private batteryChar;
|
|
55
|
+
private readonly readingListeners;
|
|
56
|
+
private readonly stateListeners;
|
|
57
|
+
onConnected(context: WebBluetoothConnectionContext): Promise<void>;
|
|
58
|
+
onDisconnected(): Promise<void>;
|
|
59
|
+
getState(): SensorState;
|
|
60
|
+
subscribe(listener: PawPrintsReadingListener): () => void;
|
|
61
|
+
onStateChanged(listener: PawPrintsStateListener): () => void;
|
|
62
|
+
/**
|
|
63
|
+
* Sends the 0x50 config/trigger command. `config` is copied into the
|
|
64
|
+
* 14-byte trailing config block (truncated if longer, zero-padded if
|
|
65
|
+
* shorter/omitted).
|
|
66
|
+
*/
|
|
67
|
+
configureTrigger(mode: number, color: number, config?: Uint8Array): Promise<void>;
|
|
68
|
+
resetParameters(): Promise<void>;
|
|
69
|
+
startAngleDetection(): Promise<void>;
|
|
70
|
+
setLedSolid(color: number): Promise<void>;
|
|
71
|
+
setLedBlink(color1: number, color2: number, speed: number): Promise<void>;
|
|
72
|
+
private resetConnection;
|
|
73
|
+
private emitState;
|
|
74
|
+
private writeCommand;
|
|
75
|
+
private readonly handleNotification;
|
|
76
|
+
private parseReading;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=paw-prints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paw-prints.d.ts","sourceRoot":"","sources":["../src/paw-prints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAA0B,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAQxE,OAAO,KAAK,EAAE,6BAA6B,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAQ1F,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3D;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1B,CAAC;AAEN,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAC3E,MAAM,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAiBlE,qBAAa,sBAAuB,YAAW,yBAAyB,CAAC,gBAAgB,CAAC;IACxF,OAAO,CAAC,KAAK,CAAyC;IACtD,OAAO,CAAC,SAAS,CAAsD;IACvE,OAAO,CAAC,UAAU,CAAsD;IACxE,OAAO,CAAC,WAAW,CAAsD;IAEzE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAuC;IACxE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqC;IAE9D,WAAW,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC;IAsClE,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC,QAAQ,IAAI,WAAW;IAIvB,SAAS,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,IAAI;IAOzD,cAAc,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM,IAAI;IAO5D;;;;OAIG;IACG,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjF,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAWjE,eAAe;IA2B7B,OAAO,CAAC,SAAS;YAOH,YAAY;IAO1B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAWjC;IAEF,OAAO,CAAC,YAAY;CA8ErB"}
|