obsbot-mcp 0.1.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.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +170 -0
  3. package/dist/capture/ffmpeg-args.d.ts +17 -0
  4. package/dist/capture/ffmpeg-args.js +48 -0
  5. package/dist/capture/ffmpeg-args.js.map +1 -0
  6. package/dist/capture/manager.d.ts +60 -0
  7. package/dist/capture/manager.js +159 -0
  8. package/dist/capture/manager.js.map +1 -0
  9. package/dist/codec/commands.d.ts +63 -0
  10. package/dist/codec/commands.js +185 -0
  11. package/dist/codec/commands.js.map +1 -0
  12. package/dist/codec/crc.d.ts +2 -0
  13. package/dist/codec/crc.js +11 -0
  14. package/dist/codec/crc.js.map +1 -0
  15. package/dist/codec/encoding.d.ts +7 -0
  16. package/dist/codec/encoding.js +8 -0
  17. package/dist/codec/encoding.js.map +1 -0
  18. package/dist/codec/frame.d.ts +20 -0
  19. package/dist/codec/frame.js +73 -0
  20. package/dist/codec/frame.js.map +1 -0
  21. package/dist/codec/opcodes.d.ts +32 -0
  22. package/dist/codec/opcodes.js +509 -0
  23. package/dist/codec/opcodes.js.map +1 -0
  24. package/dist/codec/types.d.ts +13 -0
  25. package/dist/codec/types.js +2 -0
  26. package/dist/codec/types.js.map +1 -0
  27. package/dist/device/manager.d.ts +9 -0
  28. package/dist/device/manager.js +20 -0
  29. package/dist/device/manager.js.map +1 -0
  30. package/dist/device/session.d.ts +22 -0
  31. package/dist/device/session.js +37 -0
  32. package/dist/device/session.js.map +1 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +14 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/mcp/framing.d.ts +31 -0
  37. package/dist/mcp/framing.js +45 -0
  38. package/dist/mcp/framing.js.map +1 -0
  39. package/dist/mcp/ready.d.ts +31 -0
  40. package/dist/mcp/ready.js +71 -0
  41. package/dist/mcp/ready.js.map +1 -0
  42. package/dist/mcp/render.d.ts +3 -0
  43. package/dist/mcp/render.js +14 -0
  44. package/dist/mcp/render.js.map +1 -0
  45. package/dist/mcp/server.d.ts +3 -0
  46. package/dist/mcp/server.js +49 -0
  47. package/dist/mcp/server.js.map +1 -0
  48. package/dist/mcp/tools.d.ts +12 -0
  49. package/dist/mcp/tools.js +580 -0
  50. package/dist/mcp/tools.js.map +1 -0
  51. package/dist/transport/helper-process.d.ts +39 -0
  52. package/dist/transport/helper-process.js +140 -0
  53. package/dist/transport/helper-process.js.map +1 -0
  54. package/dist/transport/transport.d.ts +62 -0
  55. package/dist/transport/transport.js +8 -0
  56. package/dist/transport/transport.js.map +1 -0
  57. package/dist/transport/windows.d.ts +34 -0
  58. package/dist/transport/windows.js +68 -0
  59. package/dist/transport/windows.js.map +1 -0
  60. package/native/prebuilt/win32-x64/obsbot-helper.exe +0 -0
  61. package/package.json +33 -0
@@ -0,0 +1,185 @@
1
+ import { buildFrame } from "./frame.js";
2
+ import { f32le, u32le, i32le, concat } from "./encoding.js";
3
+ import { OP_BY_NAME } from "./opcodes.js";
4
+ // Vendor frames are addressed by opcode NAME; the wire cmd and receiver come
5
+ // from the reverse-engineered opcode table (src/codec/opcodes.ts) rather than
6
+ // magic numbers, so the same definitions serve every platform transport and
7
+ // new commands are a table row + a payload encoder.
8
+ const vendorOp = (name, payload) => {
9
+ const op = OP_BY_NAME.get(name);
10
+ if (!op || op.wireCmd === null || op.receiver === null) {
11
+ throw new Error(`opcode "${name}" is not a sendable V3 command`);
12
+ }
13
+ const { wireCmd, receiver } = op;
14
+ return { kind: "vendor", buildFrame: (seq) => buildFrame({ seq, cmd: wireCmd, receiver, payload }) };
15
+ };
16
+ /**
17
+ * RE/diagnostics: build ANY opcode-table entry as a V3 frame with an arbitrary
18
+ * payload. Used by the obsbot_probe tool to exercise unmapped GET/query opcodes
19
+ * (e.g. AI_GET_QUICK_STATUS) while reverse-engineering the feedback surface.
20
+ */
21
+ export const encodeVendorProbe = (name, payload) => vendorOp(name, payload);
22
+ // The gimbal move wire payload order is [roll, pitch, yaw] (data[0..3]=roll,
23
+ // [4..7]=pitch, [8..11]=yaw). Sending them in logical (yaw,pitch,roll) order put yaw
24
+ // into the roll slot (roll is unused on Tiny 2), which is why move-to-angle appeared
25
+ // inert.
26
+ const gimbal3 = (name, yaw, pitch, roll) => vendorOp(name, concat(f32le(roll), f32le(pitch), f32le(yaw)));
27
+ export const encodeSetRunStatus = (state) => vendorOp("CAM_SET_DEV_STATUS", Buffer.from([state === "run" ? 0 : 1, 0, 0, 0])); // wake=0, sleep=1
28
+ export const encodePtzMoveAngle = (yaw, pitch, roll) => gimbal3("AI_SET_GIM_MOTOR_DEG", yaw, pitch, roll);
29
+ export const encodePtzMoveSpeed = (yaw, pitch, roll) => gimbal3("AI_SET_GIM_SPEED", yaw, pitch, roll);
30
+ export const encodeRecenter = () => vendorOp("GIM_SET_MOTOR", Buffer.alloc(6));
31
+ export const zoomRatioToUnits = (ratio, min, max) => Math.round(min + (max - min) * (ratio - 1.0) + 0.001);
32
+ const AI_TRACK_VIEW = {
33
+ "human-normal": [0, 0],
34
+ "human-full-body": [0, 4],
35
+ "human-half-body": [0, 3],
36
+ "human-close-up": [0, 2],
37
+ "human-auto-view": [0, 1],
38
+ "animal-normal": [1, 0],
39
+ "animal-close-up": [1, 2],
40
+ "animal-auto-view": [1, 1],
41
+ };
42
+ export const AI_TRACK_MODES = Object.keys(AI_TRACK_VIEW);
43
+ /** Enable AI tracking in a specific framing mode (AI_SET_AI_TRACK_MODE, cmd 0x6f). */
44
+ export const encodeAiTrackEnable = (mode) => {
45
+ const [subject, view] = AI_TRACK_VIEW[mode];
46
+ return vendorOp("AI_SET_AI_TRACK_MODE", concat(u32le(subject), u32le(view)));
47
+ };
48
+ /** Disable AI tracking of the current target (AI_SET_CANCEL_TARGET, cmd 0x6e — no payload). */
49
+ export const encodeAiTrackDisable = () => vendorOp("AI_SET_CANCEL_TARGET", Buffer.alloc(0));
50
+ /** Enable auto group-framing (AI_SET_AUTO_GROUP, cmd 0x70 — 8 zero bytes). */
51
+ export const encodeAiGroupEnable = () => vendorOp("AI_SET_AUTO_GROUP", Buffer.alloc(8));
52
+ /** Disable auto group-framing (AI_CANCEL_AUTO_GROUP, cmd 0x71 — no payload). */
53
+ export const encodeAiGroupDisable = () => vendorOp("AI_CANCEL_AUTO_GROUP", Buffer.alloc(0));
54
+ const AI_TRACK_SPEED = {
55
+ standard: 0, // device Standard (slower follow)
56
+ sport: 2, // device Sport (snappier follow)
57
+ };
58
+ export const AI_TRACK_SPEEDS = Object.keys(AI_TRACK_SPEED);
59
+ export const encodeAiTrackSpeed = (speed) => vendorOp("AI_SET_TRACK_MODE", Buffer.from([AI_TRACK_SPEED[speed]]));
60
+ // ---------------------------------------------------------------------------
61
+ // Zoom with speed (CAM_SET_ZOOM_ABSOLUTE, cmd 0x32)
62
+ // ---------------------------------------------------------------------------
63
+ // The zoom-with-speed payload packs speed FIRST then ratio: data[0:4] =
64
+ // u32le(zoom_speed), data[4:8] = u32le(zoom_ratio), where zoom_ratio is the
65
+ // ratio × 100 (1.5× -> 150).
66
+ export const encodeZoomWithSpeed = (ratioX100, speed) => vendorOp("CAM_SET_ZOOM_ABSOLUTE", concat(u32le(speed), u32le(ratioX100)));
67
+ // ---------------------------------------------------------------------------
68
+ // Face focus (CAM_SET_FACE_FOCUS, cmd 0x03) — int32le(enable) on V3.
69
+ // ---------------------------------------------------------------------------
70
+ export const encodeFaceFocus = (enable) => vendorOp("CAM_SET_FACE_FOCUS", i32le(enable ? 1 : 0));
71
+ // ---------------------------------------------------------------------------
72
+ // Reads (Get commands) — the return channel. A GET request carries no nested
73
+ // payload (it asks, it does not set); the camera replies with a frame whose
74
+ // payload holds the state. Decoders take that reply payload.
75
+ // ---------------------------------------------------------------------------
76
+ /** Request the current face-priority autofocus state (CAM_GET_FACE_FOCUS, cmd 0x35c2). */
77
+ export const encodeGetFaceFocus = () => vendorOp("CAM_GET_FACE_FOCUS", Buffer.alloc(0));
78
+ /** Decode a CAM_GET_FACE_FOCUS reply payload: int32le enable flag at offset 0. */
79
+ export const decodeFaceFocus = (payload) => {
80
+ if (payload.length < 4) {
81
+ throw new Error(`face-focus reply payload too short: ${payload.length} bytes`);
82
+ }
83
+ return { enabled: payload.readInt32LE(0) !== 0 };
84
+ };
85
+ // ---------------------------------------------------------------------------
86
+ // UVC extension-unit controls (XU selector 6, NOT a V3 frame)
87
+ // ---------------------------------------------------------------------------
88
+ // FOV and (UVC-mode) WDR/HDR use a fixed 60-byte buffer written via
89
+ // uvc_xu_set(selector = 6, buf, 0x3c). The first three bytes are [tag, 0x01,
90
+ // value]; the rest are zero. tag 0x04 = FOV, 0x01 = WDR/HDR.
91
+ export const UVC_XU_SELECTOR = 6;
92
+ const uvcExt = (tag, value) => {
93
+ const b = Buffer.alloc(60);
94
+ b[0] = tag;
95
+ b[1] = 0x01;
96
+ b[2] = value & 0xff;
97
+ return b;
98
+ };
99
+ const FOV_VALUE = { wide: 0, medium: 1, narrow: 2 };
100
+ export const FOV_TYPES = Object.keys(FOV_VALUE);
101
+ export const encodeFov = (fov) => uvcExt(0x04, FOV_VALUE[fov]);
102
+ // HDR/WDR on/off.
103
+ export const encodeHdr = (on) => uvcExt(0x01, on ? 1 : 0);
104
+ const AI_FRAMING = {
105
+ normal: 0,
106
+ "upper-body": 1,
107
+ "close-up": 2,
108
+ headless: 3,
109
+ "lower-body": 4,
110
+ };
111
+ export const AI_FRAMING_MODES = Object.keys(AI_FRAMING);
112
+ export const encodeAiTracking = (on, mode = "normal") => {
113
+ const b = Buffer.alloc(60);
114
+ b[0] = 0x16;
115
+ b[1] = 0x02;
116
+ b[2] = on ? 0x02 : 0x00;
117
+ b[3] = on ? AI_FRAMING[mode] : 0x00;
118
+ return b;
119
+ };
120
+ // ---------------------------------------------------------------------------
121
+ // UVC standard controls (IAMCameraControl / IAMVideoProcAmp) — property ids
122
+ // and the auto/manual flag values for focus and white balance.
123
+ // ---------------------------------------------------------------------------
124
+ export const CAMERA_CONTROL_PAN = 0; // CameraControl_Pan
125
+ export const CAMERA_CONTROL_TILT = 1; // CameraControl_Tilt
126
+ export const CAMERA_CONTROL_FOCUS = 6; // CameraControl_Focus
127
+ export const CAMERA_CONTROL_EXPOSURE = 4; // CameraControl_Exposure
128
+ export const VIDEO_PROCAMP_WHITE_BALANCE = 7; // VideoProcAmp_WhiteBalance
129
+ export const UVC_FLAG_AUTO = 1; // *_Flags_Auto
130
+ export const UVC_FLAG_MANUAL = 2; // *_Flags_Manual
131
+ export const IMAGE_CONTROL_PROP = {
132
+ brightness: 0,
133
+ contrast: 1,
134
+ hue: 2,
135
+ saturation: 3,
136
+ sharpness: 4,
137
+ "backlight-compensation": 8,
138
+ gain: 9,
139
+ };
140
+ export const IMAGE_CONTROLS = Object.keys(IMAGE_CONTROL_PROP);
141
+ /** Map a 0..100 percentage onto an inclusive [min,max] device-unit range. */
142
+ export const percentToRange = (pct, min, max) => Math.round(min + (max - min) * (pct / 100));
143
+ // ---------------------------------------------------------------------------
144
+ // Status block (UVC XU selector 6, GET_CUR) — a flat fixed-offset snapshot,
145
+ // NOT a V3 frame reply: no magic, no CRC. Offsets confirmed against the
146
+ // OpenFoxes/Tiny4Linux reference (status.rs). Extend by adding offsets here.
147
+ // ---------------------------------------------------------------------------
148
+ const STATUS_OFF_SLEEP = 0x02; // 0 = awake, 1 = sleep
149
+ const STATUS_OFF_HDR = 0x06; // 0 = off, non-zero = on
150
+ const STATUS_OFF_AI_MODE_M = 0x18; // AI mode tuple, first value
151
+ const STATUS_OFF_AI_MODE_N = 0x1c; // AI mode tuple, second value
152
+ // Track speed lives at 0x24 on the Tiny 2 — NOT the reference's 0x21 (which reads
153
+ // a constant here). Offset found + value map (0=standard, 2=sport) confirmed on
154
+ // hardware 2026-07-13 against the OBSBOT Center Standard/Sport control.
155
+ const STATUS_OFF_TRACK_SPEED = 0x24;
156
+ const AI_MODE_TABLE = {
157
+ "0,0": "no-tracking",
158
+ "2,0": "normal",
159
+ "2,1": "upper-body",
160
+ "2,2": "close-up",
161
+ "2,3": "headless",
162
+ "2,4": "lower-body",
163
+ "5,0": "desk",
164
+ "4,0": "whiteboard",
165
+ "6,0": "hand",
166
+ "1,0": "group",
167
+ };
168
+ const TRACK_SPEED_TABLE = {
169
+ 0: "standard",
170
+ 2: "sport",
171
+ };
172
+ export const decodeStatus = (block) => {
173
+ if (block.length <= STATUS_OFF_TRACK_SPEED) {
174
+ throw new Error(`status block too short: ${block.length} bytes`);
175
+ }
176
+ const m = block[STATUS_OFF_AI_MODE_M];
177
+ const n = block[STATUS_OFF_AI_MODE_N];
178
+ return {
179
+ awake: block[STATUS_OFF_SLEEP] === 0,
180
+ hdr: block[STATUS_OFF_HDR] !== 0,
181
+ aiMode: AI_MODE_TABLE[`${m},${n}`] ?? "unknown",
182
+ trackSpeed: TRACK_SPEED_TABLE[block[STATUS_OFF_TRACK_SPEED]] ?? "unknown",
183
+ };
184
+ };
185
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/codec/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** CRC-16/USB: poly 0xA001 (reflected), init 0xFFFF, refin/refout, xorout 0xFFFF. */
2
+ export declare const crc16usb: (data: Buffer) => number;
@@ -0,0 +1,11 @@
1
+ /** CRC-16/USB: poly 0xA001 (reflected), init 0xFFFF, refin/refout, xorout 0xFFFF. */
2
+ export const crc16usb = (data) => {
3
+ let crc = 0xffff;
4
+ for (const b of data) {
5
+ crc ^= b;
6
+ for (let i = 0; i < 8; i++)
7
+ crc = (crc & 1) ? (crc >>> 1) ^ 0xa001 : crc >>> 1;
8
+ }
9
+ return (crc ^ 0xffff) & 0xffff;
10
+ };
11
+ //# sourceMappingURL=crc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crc.js","sourceRoot":"","sources":["../../src/codec/crc.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAU,EAAE;IAC/C,IAAI,GAAG,GAAG,MAAM,CAAC;IACjB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,GAAG,IAAI,CAAC,CAAC;QACT,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YAAE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;AACjC,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare const f32le: (n: number) => Buffer;
2
+ export declare const u16le: (n: number) => Buffer;
3
+ export declare const u32le: (n: number) => Buffer;
4
+ export declare const i32le: (n: number) => Buffer;
5
+ export declare const hexToBuf: (h: string) => Buffer;
6
+ export declare const bufToHex: (b: Buffer) => string;
7
+ export declare const concat: (...b: Buffer[]) => Buffer;
@@ -0,0 +1,8 @@
1
+ export const f32le = (n) => { const b = Buffer.alloc(4); b.writeFloatLE(n, 0); return b; };
2
+ export const u16le = (n) => { const b = Buffer.alloc(2); b.writeUInt16LE(n & 0xffff, 0); return b; };
3
+ export const u32le = (n) => { const b = Buffer.alloc(4); b.writeUInt32LE(n >>> 0, 0); return b; };
4
+ export const i32le = (n) => { const b = Buffer.alloc(4); b.writeInt32LE(n | 0, 0); return b; };
5
+ export const hexToBuf = (h) => Buffer.from(h, "hex");
6
+ export const bufToHex = (b) => b.toString("hex");
7
+ export const concat = (...b) => Buffer.concat(b);
8
+ //# sourceMappingURL=encoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../src/codec/encoding.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3G,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACrH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAClH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/G,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACrE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,GAAG,CAAW,EAAU,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ export interface FrameOpts {
2
+ seq: number;
3
+ cmd: number;
4
+ receiver: number;
5
+ payload: Buffer;
6
+ sender?: number;
7
+ }
8
+ export declare function buildFrame(o: FrameOpts): Buffer;
9
+ export declare class FrameParseError extends Error {
10
+ constructor(message: string);
11
+ }
12
+ export interface ParsedFrame {
13
+ seq: number;
14
+ cmd: number;
15
+ receiver: number;
16
+ sender: number;
17
+ payload: Buffer;
18
+ }
19
+ /** Reverse of buildFrame: validate header + optional payload CRC and slice fields out. */
20
+ export declare function parseFrame(buf: Buffer): ParsedFrame;
@@ -0,0 +1,73 @@
1
+ import { crc16usb } from "./crc.js";
2
+ import { u16le } from "./encoding.js";
3
+ export function buildFrame(o) {
4
+ const frame = Buffer.alloc(60); // zero-padded fixed buffer
5
+ frame[0] = 0xaa;
6
+ frame[1] = 0x25; // flags: UVC + nested payload (const for v1 cmds)
7
+ u16le(o.seq).copy(frame, 2);
8
+ u16le(12).copy(frame, 4); // len = 12 (header covered by token)
9
+ // token field (6-7) stays 0 for the CRC, filled after
10
+ frame[8] = o.sender ?? 0x0a;
11
+ frame[9] = o.receiver;
12
+ u16le(o.cmd).copy(frame, 10);
13
+ // header token = CRC-16/USB over frame[0:12] with 6-7 already zero
14
+ u16le(crc16usb(frame.subarray(0, 12))).copy(frame, 6);
15
+ // nested payload segment at offset 12
16
+ if (o.payload.length > 0) {
17
+ const len2 = o.payload.length;
18
+ u16le(len2).copy(frame, 12); // len2
19
+ // token2 field (14-15) zero for CRC
20
+ o.payload.copy(frame, 16);
21
+ const seg = frame.subarray(12, 12 + len2 + 4); // len2(2)+token2(2)+payload(len2)
22
+ u16le(crc16usb(seg)).copy(frame, 14);
23
+ }
24
+ return frame;
25
+ }
26
+ export class FrameParseError extends Error {
27
+ constructor(message) {
28
+ super(message);
29
+ this.name = "FrameParseError";
30
+ }
31
+ }
32
+ /** Reverse of buildFrame: validate header + optional payload CRC and slice fields out. */
33
+ export function parseFrame(buf) {
34
+ if (buf.length < 12)
35
+ throw new FrameParseError(`frame too short: ${buf.length} bytes`);
36
+ if (buf[0] !== 0xaa)
37
+ throw new FrameParseError(`bad magic: 0x${buf[0].toString(16)}`);
38
+ // Header CRC covers bytes [0,12) with the token field (6-7) treated as zero.
39
+ const hdr = Buffer.from(buf.subarray(0, 12));
40
+ hdr[6] = 0;
41
+ hdr[7] = 0;
42
+ const wantHdr = crc16usb(hdr);
43
+ const gotHdr = buf.readUInt16LE(6);
44
+ if (gotHdr !== wantHdr) {
45
+ throw new FrameParseError(`header CRC mismatch: got 0x${gotHdr.toString(16)} want 0x${wantHdr.toString(16)}`);
46
+ }
47
+ const seq = buf.readUInt16LE(2);
48
+ const sender = buf[8];
49
+ const receiver = buf[9];
50
+ const cmd = buf.readUInt16LE(10);
51
+ let payload = Buffer.alloc(0);
52
+ if (buf.length >= 16) {
53
+ const len2 = buf.readUInt16LE(12);
54
+ if (len2 > 0) {
55
+ const end = 16 + len2;
56
+ if (buf.length < end) {
57
+ throw new FrameParseError(`truncated payload: need ${end} bytes, have ${buf.length}`);
58
+ }
59
+ // Payload CRC covers [12,end) with the token2 field (14-15) treated as zero.
60
+ const seg = Buffer.from(buf.subarray(12, end));
61
+ seg[2] = 0; // frame offset 14
62
+ seg[3] = 0; // frame offset 15
63
+ const wantSeg = crc16usb(seg);
64
+ const gotSeg = buf.readUInt16LE(14);
65
+ if (gotSeg !== wantSeg) {
66
+ throw new FrameParseError(`payload CRC mismatch: got 0x${gotSeg.toString(16)} want 0x${wantSeg.toString(16)}`);
67
+ }
68
+ payload = Buffer.from(buf.subarray(16, end));
69
+ }
70
+ }
71
+ return { seq, cmd, receiver, sender, payload };
72
+ }
73
+ //# sourceMappingURL=frame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame.js","sourceRoot":"","sources":["../../src/codec/frame.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /** One vendor command and its wire addressing. */
2
+ export interface Opcode {
3
+ /** Command enum member name, e.g. "AI_SET_GIM_SPEED". */
4
+ name: string;
5
+ /** Subsystem group: "Camera" | "Ai" | "Gimbal" | "SysMg" | "TXBle" | ... */
6
+ subsystem: string;
7
+ /** Logical command set (CmdSet enum value). */
8
+ set: number;
9
+ /** Logical command id within the subsystem (Cmd<Sub> enum value). */
10
+ cmdId: number;
11
+ /** 16-bit wire cmd (frame bytes 10-11, little-endian), or null if V0-only. */
12
+ wireCmd: number | null;
13
+ /** Receiver byte (frame byte 9), or null if V0-only. */
14
+ receiver: number | null;
15
+ }
16
+ export declare const OPCODES: readonly Opcode[];
17
+ /** Lookup by enum-member name (e.g. OP_BY_NAME.get("AI_SET_GIM_SPEED")). */
18
+ export declare const OP_BY_NAME: ReadonlyMap<string, Opcode>;
19
+ /** Commands sendable over the V3 wire protocol (have a concrete wireCmd). */
20
+ export declare const SENDABLE: readonly Opcode[];
21
+ /**
22
+ * Names of commands that can brick the device, erase user data, flash firmware,
23
+ * reset to factory state, cut power, or run arbitrary code. Any code path that
24
+ * dispatches an opcode by name (e.g. a future vendorOp/raw-command tool) MUST
25
+ * refuse — or require explicit human confirmation — when the name is in here.
26
+ * These are the same commands cordoned off at the end of OPCODES above.
27
+ */
28
+ export declare const DESTRUCTIVE_NAMES: ReadonlySet<string>;
29
+ /** True when the named command is potentially destructive (see DESTRUCTIVE_NAMES). */
30
+ export declare const isDestructive: (name: string) => boolean;
31
+ /** The potentially-destructive opcodes, cordoned off from the rest of the table. */
32
+ export declare const DESTRUCTIVE: readonly Opcode[];