1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
import dgram from "node:dgram";
export class XPlane {
constructor(
xplaneAddr = "localhost",
xplanePort = 49000,
statusCheck = 5000,
statusTimeout = 1000,
) {
this.socket = dgram.createSocket("udp4");
this.subscribed = [];
this.lastReceived = null;
const xplane = this;
this.statusChecker = setTimeout(async function statusChecker() {
let active = false;
if (xplane.lastReceived) {
if (new Date() - xplane.lastReceived < statusTimeout) {
active = true;
}
}
if (!active) {
//console.info(
// `x-plane data not detected, will try again in ${(statusCheck / 1000).toFixed(2)} secs`,
//);
await xplane._subscribeAll();
}
xplane.statusChecker = setTimeout(statusChecker, statusCheck);
}, statusCheck);
this.xplaneAddr = xplaneAddr;
this.xplanePort = xplanePort;
this.socket.on("message", async (msg, rinfo) => {
if (msg.subarray(0, 5).toString() != "RREF,") {
console.info("dropping unrelated message");
return;
}
this.lastReceived = new Date();
let num = (msg.length - 5) / 8;
for (let i = 0; i < num; i++) {
const idx = msg.readInt32LE(5 + i * 8);
if (idx < 0) {
console.info(`sender index ${idx} should be >= 0`);
return;
}
if (idx >= this.subscribed.length) {
console.info(`sender index ${idx} > subscribed.length`);
return;
}
const v = msg.readFloatLE(9 + i * 8);
//console.info(`${this.subscribed[idx].dataRef} = ${v}`);
await this.subscribed[idx].handler(v);
}
});
this.socket.bind(0);
}
async _subscribeDataRef(idx) {
const { dataRef, freq } = this.subscribed[idx];
let buffer = Buffer.alloc(4 + 1 + 4 * 2 + 400);
let off = buffer.write("RREF");
off = buffer.writeUInt8(0, off); // null terminated
off = buffer.writeInt32LE(freq, off); // xint frequency
off = buffer.writeInt32LE(idx, off); // xint sender index
off += buffer.write(dataRef, off); // char[400] dataref
off = buffer.writeUInt8(0, off); // null terminated
await this.socket.send(
buffer,
0,
buffer.length,
this.xplanePort,
this.xplaneAddr,
);
}
async _subscribeAll() {
for (let i = 0; i < this.subscribed.length; i++) {
await this._subscribeDataRef(i);
}
}
async subscribeDataRef(dataRef, freq, handler) {
const idx = this.subscribed.length;
if (handler) {
this.subscribed.push({ dataRef, handler, freq });
}
console.info(`x-plane subscribed[${idx}] => ${dataRef}`);
this._subscribeDataRef(idx);
}
//subscribeDataRef("sim/flightmodel/position/indicated_airspeed");
async sendCommand(cmd) {
let buffer = Buffer.alloc(4 + 1 + cmd.length + 1);
let off = buffer.write("CMND");
off = buffer.writeUInt8(0, off); // null terminated
off += buffer.write(cmd, off); // command
off = buffer.writeUInt8(0, off); // null terminated
console.info(`x-plane cmd: ${cmd}`);
await this.socket.send(
buffer,
0,
buffer.length,
this.xplanePort,
this.xplaneAddr,
);
}
//sendCommand("sim/GPS/g1000n1_hdg_down");
async close() {
for (let i = 0; i < this.subscribed.length; i++) {
this.subscribed[i].freq = 0;
await this._subscribeDataRef(i);
}
this.subscribed = [];
clearTimeout(this.statusChecker);
}
}
|