more refactor
This commit is contained in:
+11
-24
@@ -3,16 +3,7 @@ import { RemoteInfo } from "node:dgram";
|
|||||||
import { Commands, CommandsByValue, ControlCommands } from "./datatypes.js";
|
import { Commands, CommandsByValue, ControlCommands } from "./datatypes.js";
|
||||||
import { XqBytesDec } from "./func_replacements.js";
|
import { XqBytesDec } from "./func_replacements.js";
|
||||||
import { hexdump } from "./hexdump.js";
|
import { hexdump } from "./hexdump.js";
|
||||||
import {
|
import { create_P2pRdy, SendListWifi, SendUsrChk } from "./impl.js";
|
||||||
create_P2pClose,
|
|
||||||
create_P2pRdy,
|
|
||||||
SendDevStatus,
|
|
||||||
SendListWifi,
|
|
||||||
SendReboot,
|
|
||||||
SendStartVideo,
|
|
||||||
SendUsrChk,
|
|
||||||
SendWifiSettings,
|
|
||||||
} from "./impl.js";
|
|
||||||
import { Session } from "./session.js";
|
import { Session } from "./session.js";
|
||||||
import { u16_swap, u32_swap } from "./utils.js";
|
import { u16_swap, u32_swap } from "./utils.js";
|
||||||
|
|
||||||
@@ -53,14 +44,14 @@ export const handle_PunchPkt = (session: Session, dv: DataView, rinfo: RemoteInf
|
|||||||
session.send(create_P2pRdy(dv.add(4).readByteArray(len)));
|
session.send(create_P2pRdy(dv.add(4).readByteArray(len)));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createResponseForControlCommand = (session: Session, dv: DataView): DataView | undefined => {
|
export const createResponseForControlCommand = (session: Session, dv: DataView): DataView[] => {
|
||||||
const start_type = dv.add(8).readU16(); // 0xa11 on control; data starts here on DATA pkt
|
const start_type = dv.add(8).readU16(); // 0xa11 on control; data starts here on DATA pkt
|
||||||
const cmd_id = dv.add(10).readU16(); // 0x1120
|
const cmd_id = dv.add(10).readU16(); // 0x1120
|
||||||
const payload_len = u16_swap(dv.add(0xc).readU16());
|
const payload_len = u16_swap(dv.add(0xc).readU16());
|
||||||
|
|
||||||
if (start_type != 0x110a) {
|
if (start_type != 0x110a) {
|
||||||
console.error(`Expected start_type to be 0xa11, got 0x${start_type.toString(16)}`);
|
console.error(`Expected start_type to be 0xa11, got 0x${start_type.toString(16)}`);
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
const rotate_chr = 4;
|
const rotate_chr = 4;
|
||||||
if (payload_len > rotate_chr) {
|
if (payload_len > rotate_chr) {
|
||||||
@@ -73,11 +64,12 @@ export const createResponseForControlCommand = (session: Session, dv: DataView):
|
|||||||
if (cmd_id == ControlCommands.ConnectUserAck) {
|
if (cmd_id == ControlCommands.ConnectUserAck) {
|
||||||
let c = new Uint8Array(dv.add(0x18).readByteArray(4).buffer);
|
let c = new Uint8Array(dv.add(0x18).readByteArray(4).buffer);
|
||||||
session.ticket = [...c];
|
session.ticket = [...c];
|
||||||
const buf = SendStartVideo(session);
|
session.eventEmitter.emit("login");
|
||||||
return buf;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_id == ControlCommands.DevStatusAck) {
|
if (cmd_id == ControlCommands.DevStatusAck) {
|
||||||
|
// ParseDevStatus -> offset relevant?
|
||||||
let charging = u32_swap(dv.add(0x28).readU32()) & 1; // 0x14000101 v 0x14000100
|
let charging = u32_swap(dv.add(0x28).readU32()) & 1; // 0x14000101 v 0x14000100
|
||||||
let power = u16_swap(dv.add(0x18).readU16()); // '3730' or '3765', milliVolts?
|
let power = u16_swap(dv.add(0x18).readU16()); // '3730' or '3765', milliVolts?
|
||||||
let dbm = dv.add(0x24).readU8() - 0x100; // 0xbf - 0x100 = -65dbm .. constant??
|
let dbm = dv.add(0x24).readU8() - 0x100; // 0xbf - 0x100 = -65dbm .. constant??
|
||||||
@@ -104,12 +96,7 @@ export const createResponseForControlCommand = (session: Session, dv: DataView):
|
|||||||
};
|
};
|
||||||
const buf = SendListWifi(session);
|
const buf = SendListWifi(session);
|
||||||
console.log(`Current wifi settings: ${JSON.stringify(wifiSettings, null, 2)}`);
|
console.log(`Current wifi settings: ${JSON.stringify(wifiSettings, null, 2)}`);
|
||||||
setTimeout(() => {
|
return [buf];
|
||||||
console.log("send now??");
|
|
||||||
const buf = SendListWifi(session);
|
|
||||||
session.send(buf);
|
|
||||||
}, 8000);
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_id == ControlCommands.ListWifiAck) {
|
if (cmd_id == ControlCommands.ListWifiAck) {
|
||||||
@@ -138,6 +125,7 @@ export const createResponseForControlCommand = (session: Session, dv: DataView):
|
|||||||
items.push(wifiListItem);
|
items.push(wifiListItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
let seq = 0;
|
let seq = 0;
|
||||||
@@ -184,7 +172,8 @@ const deal_with_data = (session: Session, dv: DataView) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pkt_id > seq + 1) {
|
if (pkt_id > seq + 1) {
|
||||||
// missed some packets -- filling with zeroes still produces a broken image
|
// missed some packets -- filling with zeroes still produces a broken
|
||||||
|
// image
|
||||||
frame_is_bad = true;
|
frame_is_bad = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -221,8 +210,6 @@ export const handle_Drw = (session: Session, dv: DataView) => {
|
|||||||
deal_with_data(session, dv);
|
deal_with_data(session, dv);
|
||||||
} else {
|
} else {
|
||||||
const b = createResponseForControlCommand(session, dv);
|
const b = createResponseForControlCommand(session, dv);
|
||||||
if (b != undefined) {
|
b.forEach(session.send);
|
||||||
session.send(b);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ const makeDataReadWrite = (session: Session, command: number, data: DataView | n
|
|||||||
ret.add(20).writeByteArray(bufCopy);
|
ret.add(20).writeByteArray(bufCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session.outgoingCommandId++;
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ export const getVideoKey = (session: Session): void => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SendVideoResolution = (session: Session, resol: 1 | 2 | 3 | 4): null => {
|
export const SendVideoResolution = (session: Session, resol: 1 | 2 | 3 | 4): DataView[] => {
|
||||||
// seems like 0x1 = resolution, and is specified by ID not by size
|
// seems like 0x1 = resolution, and is specified by ID not by size
|
||||||
// unclear what 0x2-0xf achieve - they report back as '0' always -- ignored?
|
// unclear what 0x2-0xf achieve - they report back as '0' always -- ignored?
|
||||||
const pairs = {
|
const pairs = {
|
||||||
@@ -103,11 +104,10 @@ export const SendVideoResolution = (session: Session, resol: 1 | 2 | 3 | 4): nul
|
|||||||
// maybe the 0x7 = bitrate??
|
// maybe the 0x7 = bitrate??
|
||||||
};
|
};
|
||||||
|
|
||||||
pairs[resol].forEach((payload: number[]) => {
|
return pairs[resol].map((payload: number[]) => {
|
||||||
const dv = new DataView(new Uint8Array(payload).buffer);
|
const dv = new DataView(new Uint8Array(payload).buffer);
|
||||||
session.send(makeDataReadWrite(session, ControlCommands.VideoParamSet, dv));
|
return makeDataReadWrite(session, ControlCommands.VideoParamSet, dv);
|
||||||
});
|
});
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SendReboot = (session: Session): DataView => {
|
export const SendReboot = (session: Session): DataView => {
|
||||||
|
|||||||
+16
-3
@@ -4,6 +4,7 @@ import { Commands, CommandsByValue } from "./datatypes.js";
|
|||||||
import { handle_P2PAlive, handle_PunchPkt, handle_P2PRdy, handle_Drw, notImpl, noop } from "./handlers.js";
|
import { handle_P2PAlive, handle_PunchPkt, handle_P2PRdy, handle_Drw, notImpl, noop } from "./handlers.js";
|
||||||
import { hexdump } from "./hexdump.js";
|
import { hexdump } from "./hexdump.js";
|
||||||
import EventEmitter from "node:events";
|
import EventEmitter from "node:events";
|
||||||
|
import { SendVideoResolution, SendStartVideo, SendWifiDetails } from "./impl.js";
|
||||||
|
|
||||||
export type Session = {
|
export type Session = {
|
||||||
send: (msg: DataView) => void;
|
send: (msg: DataView) => void;
|
||||||
@@ -14,6 +15,7 @@ export type Session = {
|
|||||||
dst_ip: string;
|
dst_ip: string;
|
||||||
lastReceivedPacket: number;
|
lastReceivedPacket: number;
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
|
devName: string;
|
||||||
timers: ReturnType<typeof setInterval>[];
|
timers: ReturnType<typeof setInterval>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,6 +84,7 @@ export const makeSession = (handlers: Record<keyof typeof Commands, PacketHandle
|
|||||||
eventEmitter: new EventEmitter(),
|
eventEmitter: new EventEmitter(),
|
||||||
connected: false,
|
connected: false,
|
||||||
timers: [],
|
timers: [],
|
||||||
|
devName: "",
|
||||||
send: (msg: DataView) => {
|
send: (msg: DataView) => {
|
||||||
const raw = msg.readU16();
|
const raw = msg.readU16();
|
||||||
const cmd = CommandsByValue[raw];
|
const cmd = CommandsByValue[raw];
|
||||||
@@ -91,9 +94,6 @@ export const makeSession = (handlers: Record<keyof typeof Commands, PacketHandle
|
|||||||
console.log(hexdump(msg.buffer, { ansi: options.ansi, ansiColor: 0 }));
|
console.log(hexdump(msg.buffer, { ansi: options.ansi, ansiColor: 0 }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (raw == Commands.Drw) {
|
|
||||||
session.outgoingCommandId++;
|
|
||||||
}
|
|
||||||
sock.send(new Uint8Array(msg.buffer), SEND_PORT, session.dst_ip);
|
sock.send(new Uint8Array(msg.buffer), SEND_PORT, session.dst_ip);
|
||||||
},
|
},
|
||||||
broadcast: (msg: DataView) => {
|
broadcast: (msg: DataView) => {
|
||||||
@@ -115,6 +115,7 @@ export const makeSession = (handlers: Record<keyof typeof Commands, PacketHandle
|
|||||||
session.outgoingCommandId = 0;
|
session.outgoingCommandId = 0;
|
||||||
session.dst_ip = rinfo.address;
|
session.dst_ip = rinfo.address;
|
||||||
session.connected = true;
|
session.connected = true;
|
||||||
|
session.devName = name;
|
||||||
|
|
||||||
const int = setInterval(() => {
|
const int = setInterval(() => {
|
||||||
const delta = Date.now() - session.lastReceivedPacket;
|
const delta = Date.now() - session.lastReceivedPacket;
|
||||||
@@ -128,9 +129,21 @@ export const makeSession = (handlers: Record<keyof typeof Commands, PacketHandle
|
|||||||
}, 400);
|
}, 400);
|
||||||
session.timers.push(int);
|
session.timers.push(int);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
session.eventEmitter.on("login", () => {
|
||||||
|
console.log(`Logged in - ${session.devName}`);
|
||||||
|
startVideoStream(session);
|
||||||
|
});
|
||||||
return session;
|
return session;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const startVideoStream = (s: Session) => {
|
||||||
|
[
|
||||||
|
...SendVideoResolution(s, 2), // 640x480
|
||||||
|
SendStartVideo(s),
|
||||||
|
].forEach(s.send);
|
||||||
|
};
|
||||||
|
|
||||||
export const Handlers: Record<keyof typeof Commands, PacketHandler> = {
|
export const Handlers: Record<keyof typeof Commands, PacketHandler> = {
|
||||||
PunchPkt: handle_PunchPkt,
|
PunchPkt: handle_PunchPkt,
|
||||||
P2PAlive: handle_P2PAlive,
|
P2PAlive: handle_P2PAlive,
|
||||||
|
|||||||
+9
-8
@@ -5,7 +5,7 @@ import assert from "assert";
|
|||||||
import { XqBytesDec, XqBytesEnc } from "../func_replacements.js";
|
import { XqBytesDec, XqBytesEnc } from "../func_replacements.js";
|
||||||
import { createResponseForControlCommand } from "../handlers.js";
|
import { createResponseForControlCommand } from "../handlers.js";
|
||||||
import { hexdump } from "../hexdump.js";
|
import { hexdump } from "../hexdump.js";
|
||||||
import { SendDevStatus, SendUsrChk, SendWifiDetails } from "../impl.ts";
|
import { SendStartVideo, SendDevStatus, SendUsrChk, SendWifiDetails } from "../impl.ts";
|
||||||
import { placeholderTypes, sprintf } from "../utils.js";
|
import { placeholderTypes, sprintf } from "../utils.js";
|
||||||
|
|
||||||
describe("debug_tools", () => {
|
describe("debug_tools", () => {
|
||||||
@@ -123,6 +123,11 @@ describe("module", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const hstrToBA = (hs) => new Uint8Array(hs.match(/../g).map((h) => parseInt(h, 16))).buffer;
|
const hstrToBA = (hs) => new Uint8Array(hs.match(/../g).map((h) => parseInt(h, 16))).buffer;
|
||||||
|
describe("events", () => {
|
||||||
|
it("emits login event upon logging in", () => {
|
||||||
|
// TODO
|
||||||
|
});
|
||||||
|
});
|
||||||
describe("make packet", () => {
|
describe("make packet", () => {
|
||||||
it("builds a good SendUsrChk", () => {
|
it("builds a good SendUsrChk", () => {
|
||||||
const expected_str =
|
const expected_str =
|
||||||
@@ -132,16 +137,12 @@ describe("make packet", () => {
|
|||||||
assert.deepEqual(SendUsrChk(sess, "admin", "admin").buffer, expected);
|
assert.deepEqual(SendUsrChk(sess, "admin", "admin").buffer, expected);
|
||||||
});
|
});
|
||||||
it("builds a good SendStartVideo", () => {
|
it("builds a good SendStartVideo", () => {
|
||||||
const input_pkt_str = "f1d00018d1000000110a20110c00ff000000000064504737fe010101";
|
const _expected_str = "f1d00010d1000000110a10300400000001020304";
|
||||||
// token-in = 0x64 0x50 0x47 0x37
|
|
||||||
const _expected_str = "f1d00010d1000000110a10300400000065514636";
|
|
||||||
// output is 0x3010; 'start video'; hardcoded but shouldnt
|
|
||||||
const expected = hstrToBA(_expected_str);
|
const expected = hstrToBA(_expected_str);
|
||||||
|
|
||||||
const sess = { outgoingCommandId: 0, ticket: [0, 0, 0, 0] };
|
const sess = { outgoingCommandId: 0, ticket: [1, 2, 3, 4] };
|
||||||
const got = createResponseForControlCommand(sess, new DataView(hstrToBA(input_pkt_str)));
|
const got = SendStartVideo(sess);
|
||||||
assert.deepEqual(got.buffer, expected);
|
assert.deepEqual(got.buffer, expected);
|
||||||
assert.deepEqual(sess.ticket, [0x65, 0x51, 0x46, 0x36]);
|
|
||||||
});
|
});
|
||||||
it("builds a good SendDevStatus", () => {
|
it("builds a good SendDevStatus", () => {
|
||||||
const sess = { outgoingCommandId: 0, ticket: [1, 2, 3, 4] };
|
const sess = { outgoingCommandId: 0, ticket: [1, 2, 3, 4] };
|
||||||
|
|||||||
Reference in New Issue
Block a user