mirror of
https://github.com/jwetzell/psn-js.git
synced 2026-09-01 20:39:25 +00:00
remove binary-parsser lib dependency
This commit is contained in:
@@ -14,5 +14,6 @@ module.exports = {
|
|||||||
'class-methods-use-this': 'off',
|
'class-methods-use-this': 'off',
|
||||||
'import/extensions': 'off',
|
'import/extensions': 'off',
|
||||||
'import/no-relative-packages': 'off',
|
'import/no-relative-packages': 'off',
|
||||||
|
'no-param-reassign': 'off',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ js implementation of the [PosiStageNet protocol](https://github.com/vyv/psn-cpp/
|
|||||||
const { Decoder } = require('@jwetzell/posistagenet')
|
const { Decoder } = require('@jwetzell/posistagenet')
|
||||||
const decoder = new Decoder()
|
const decoder = new Decoder()
|
||||||
|
|
||||||
const buffer = Buffer.from('source PSN packets from somewhere')
|
const infoPacketBuffer = Buffer.from('5667348000000c0001000000000000000203010101000b00536572766572204e616d650200118001000d8000000900547261636b65722031','hex')
|
||||||
|
const dataPacketBuffer = Buffer.from('5567288000000c00010000000000000002030101010014800100108000000c000000803f0000803f0000803f','hex')
|
||||||
|
|
||||||
decoder.decode(buffer)
|
decoder.decode(infoPacketBuffer)
|
||||||
|
decoder.decode(dataPacketBuffer)
|
||||||
|
|
||||||
// data from PSN Info packets
|
// the system_name from info packets if available
|
||||||
console.log(decoder.info)
|
console.log(decoder.system_name)
|
||||||
|
|
||||||
// data from PSN Data packets
|
// map of trackers populated with any data that has been received
|
||||||
console.log(decoder.data)
|
// this merges both info and data packet properties into one
|
||||||
|
console.log(decoder.trackers)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -56,3 +59,6 @@ infoPackets.forEach((infoPacket)=>{
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- UInt64
|
||||||
|
- PosiStageNet uses 64 bit UInt's for timestamp values make sure to use [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) if using values over `Number.MAX_SAFE_INTEGER`
|
||||||
+14
-11
@@ -1,3 +1,4 @@
|
|||||||
|
// recreation of psn_client.cpp example from https://github.com/vyv/psn-cpp
|
||||||
const dgram = require('dgram');
|
const dgram = require('dgram');
|
||||||
const { Decoder } = require('..');
|
const { Decoder } = require('..');
|
||||||
|
|
||||||
@@ -14,29 +15,29 @@ client.on('message', (buffer) => {
|
|||||||
client.bind(56565, '0.0.0.0');
|
client.bind(56565, '0.0.0.0');
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if (decoder.info.system_name) {
|
if (decoder.system_name) {
|
||||||
console.log(`System Name: ${decoder.info.system_name}`);
|
console.log(`System Name: ${decoder.system_name}`);
|
||||||
}
|
}
|
||||||
if (Object.keys(decoder.info.trackers).length > 0) {
|
if (Object.keys(decoder.trackers).length > 0) {
|
||||||
console.log(`Tracker Count: ${Object.keys(decoder.info.trackers).length}`);
|
console.log(`Tracker Count: ${Object.keys(decoder.trackers).length}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.entries(decoder.data.trackers).forEach(([trackerId, tracker]) => {
|
Object.entries(decoder.trackers).forEach(([trackerId, tracker]) => {
|
||||||
console.log(
|
console.log(
|
||||||
`Tracker - id: ${trackerId} | name: ${
|
`Tracker - id: ${trackerId} | name: ${
|
||||||
decoder.info.trackers[trackerId]?.name ? decoder.info.trackers[trackerId]?.name : ''
|
decoder.trackers[trackerId]?.tracker_name ? decoder.trackers[trackerId]?.tracker_name : ''
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
if (tracker.pos) {
|
if (tracker.pos) {
|
||||||
console.log(`\tpos: ${tracker.pos.x}, ${tracker.pos.y}, ${tracker.pos.z}`);
|
console.log(`\tpos: ${tracker.pos.pos_x}, ${tracker.pos.pos_y}, ${tracker.pos.pos_z}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracker.speed) {
|
if (tracker.speed) {
|
||||||
console.log(`\tspeed: ${tracker.speed.x}, ${tracker.speed.y}, ${tracker.speed.z}`);
|
console.log(`\tspeed: ${tracker.speed.speed_x}, ${tracker.speed.speed_y}, ${tracker.speed.speed_z}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracker.ori) {
|
if (tracker.ori) {
|
||||||
console.log(`\tori: ${tracker.ori.x}, ${tracker.ori.y}, ${tracker.ori.z}`);
|
console.log(`\tori: ${tracker.ori.ori_x}, ${tracker.ori.ori_y}, ${tracker.ori.ori_z}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracker.status) {
|
if (tracker.status) {
|
||||||
@@ -44,11 +45,13 @@ setInterval(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tracker.accel) {
|
if (tracker.accel) {
|
||||||
console.log(`\taccel: ${tracker.accel.x}, ${tracker.accel.y}, ${tracker.accel.z}`);
|
console.log(`\taccel: ${tracker.accel.accel_x}, ${tracker.accel.accel_y}, ${tracker.accel.accel_z}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracker.trgtpos) {
|
if (tracker.trgtpos) {
|
||||||
console.log(`\ttrgtpos: ${tracker.trgtpos.x}, ${tracker.trgtpos.y}, ${tracker.trgtpos.z}`);
|
console.log(
|
||||||
|
`\ttrgtpos: ${tracker.trgtpos.trgtpos_x}, ${tracker.trgtpos.trgtpos_y}, ${tracker.trgtpos.trgtpos_z}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracker.timestamp) {
|
if (tracker.timestamp) {
|
||||||
|
|||||||
+18
-8
@@ -1,8 +1,10 @@
|
|||||||
|
// recreation of psn_server.cpp example from https://github.com/vyv/psn-cpp
|
||||||
const dgram = require('dgram');
|
const dgram = require('dgram');
|
||||||
const { Encoder, Tracker } = require('..');
|
const { Encoder, Tracker, Decoder } = require('..');
|
||||||
|
|
||||||
const client = dgram.createSocket('udp4');
|
const client = dgram.createSocket('udp4');
|
||||||
const encoder = new Encoder('Test PSN Server', 2, 0);
|
const encoder = new Encoder('Test PSN Server', 2, 0);
|
||||||
|
const decoder = new Decoder();
|
||||||
|
|
||||||
const trackers = [];
|
const trackers = [];
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ const distFromSun = [0, 0.58, 1.08, 1.5, 2.28, 7.78, 14.29, 28.71, 45.04, 59.13]
|
|||||||
|
|
||||||
let timestamp = 0;
|
let timestamp = 0;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
for (let index = 0; index < trackers.length; index += 1) {
|
orbits.forEach((orbit, index) => {
|
||||||
const a = 1.0 / orbits[index];
|
const a = 1.0 / orbits[index];
|
||||||
const b = distFromSun[index];
|
const b = distFromSun[index];
|
||||||
const x = timestamp;
|
const x = timestamp;
|
||||||
@@ -36,19 +38,27 @@ setInterval(() => {
|
|||||||
trackers[index].setTrgtPos(3, 14, 16);
|
trackers[index].setTrgtPos(3, 14, 16);
|
||||||
trackers[index].setStatus(index / 10.0);
|
trackers[index].setStatus(index / 10.0);
|
||||||
trackers[index].setTimestamp(timestamp);
|
trackers[index].setTimestamp(timestamp);
|
||||||
}
|
});
|
||||||
|
|
||||||
const dataPackets = encoder.getDataPackets(timestamp, trackers);
|
const dataPackets = encoder.getDataPackets(timestamp, trackers);
|
||||||
|
dataPackets.forEach((packet, index) => {
|
||||||
dataPackets.forEach((packet) => {
|
const decodedPacket = decoder.decode(packet);
|
||||||
|
console.log(
|
||||||
|
`Sending PSN_DATA_PACKET : Frame Id = ${decodedPacket.packet_header.frame_id} , Packet Count = ${index + 1}`
|
||||||
|
);
|
||||||
client.send(packet, 56565, '236.10.10.10');
|
client.send(packet, 56565, '236.10.10.10');
|
||||||
});
|
});
|
||||||
timestamp += 1;
|
timestamp += 1;
|
||||||
}, 20);
|
}, 5);
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const infoPackets = encoder.getInfoPackets(timestamp, trackers);
|
const infoPackets = encoder.getInfoPackets(timestamp, trackers);
|
||||||
infoPackets.forEach((packet) => {
|
infoPackets.forEach((packet, index) => {
|
||||||
|
const decodedPacket = decoder.decode(packet);
|
||||||
|
console.log(
|
||||||
|
`Sending PSN_INFO_PACKET : Frame Id = ${decodedPacket.packet_header.frame_id} , Packet Count = ${index + 1}`
|
||||||
|
);
|
||||||
|
|
||||||
client.send(packet, 56565, '236.10.10.10');
|
client.send(packet, 56565, '236.10.10.10');
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 500);
|
||||||
|
|||||||
Generated
-11
@@ -8,9 +8,6 @@
|
|||||||
"name": "@jwetzell/posistagenet",
|
"name": "@jwetzell/posistagenet",
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
|
||||||
"binary-parser": "^2.2.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.48.0",
|
"eslint": "^8.48.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
@@ -429,14 +426,6 @@
|
|||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/binary-parser": {
|
|
||||||
"version": "2.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/binary-parser/-/binary-parser-2.2.1.tgz",
|
|
||||||
"integrity": "sha512-5ATpz/uPDgq5GgEDxTB4ouXCde7q2lqAQlSdBRQVl/AJnxmQmhIfyxJx+0MGu//D5rHQifkfGbWWlaysG0o9NA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
|||||||
+1
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@jwetzell/posistagenet",
|
"name": "@jwetzell/posistagenet",
|
||||||
"version": "0.2.1",
|
"version": "0.3.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -19,8 +19,5 @@
|
|||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"prettier": "^3.0.3"
|
"prettier": "^3.0.3"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"binary-parser": "^2.2.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
PACKET_HEADER_SIZE: 16,
|
||||||
|
MAX_UDP_PACKET_SIZE: 1500,
|
||||||
|
CHUNK_HEADER_SIZE: 4,
|
||||||
|
};
|
||||||
+49
-71
@@ -1,8 +1,7 @@
|
|||||||
const PacketParser = require('./decoders/packet');
|
const packetDecoder = require('./decoders/packet');
|
||||||
const InfoPacket = require('./models/packets/info-packet');
|
|
||||||
const DataPacket = require('./models/packets/data-packet');
|
|
||||||
|
|
||||||
class Decoder {
|
class Decoder {
|
||||||
|
// TODO(jwetzell): check if these last packet headers are necessary to hold on to
|
||||||
lastInfoPacketHeader;
|
lastInfoPacketHeader;
|
||||||
|
|
||||||
lastDataPacketHeader;
|
lastDataPacketHeader;
|
||||||
@@ -12,74 +11,58 @@ class Decoder {
|
|||||||
dataPacketFrames = {};
|
dataPacketFrames = {};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.info = {
|
this.system_name = '';
|
||||||
trackers: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
this.data = {
|
this.trackers = {};
|
||||||
trackers: {},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateInfo(framePackets) {
|
updateInfo(framePackets) {
|
||||||
framePackets.forEach((packet) => {
|
framePackets.forEach((packet) => {
|
||||||
packet.subChunks?.forEach((subChunk) => {
|
if (packet.system_name) {
|
||||||
if (subChunk.id === 0x0001) {
|
this.system_name = packet.system_name.system_name;
|
||||||
// NOTE(jwetzell): system name subChunk
|
}
|
||||||
this.info.system_name = subChunk.system_name;
|
|
||||||
} else if (subChunk.id === 0x0002) {
|
if (packet.tracker_list?.trackers) {
|
||||||
subChunk.trackers?.forEach((tracker) => {
|
Object.entries(packet.tracker_list.trackers).forEach(([trackerId, tracker]) => {
|
||||||
if (this.info.trackers[tracker.id] === undefined) {
|
this.trackers[trackerId] = {
|
||||||
this.info.trackers[tracker.id] = {};
|
...this.trackers[trackerId],
|
||||||
}
|
...tracker.tracker_name,
|
||||||
this.info.trackers[tracker.id].name = tracker.tracker_name.tracker_name;
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateData(framePackets) {
|
updateData(framePackets) {
|
||||||
framePackets.forEach((packet) => {
|
framePackets.forEach((packet) => {
|
||||||
packet.subChunks?.forEach((subChunk) => {
|
if (packet.tracker_list) {
|
||||||
if (subChunk.id === 0x0001) {
|
Object.entries(packet.tracker_list.trackers).forEach(([trackerId, tracker]) => {
|
||||||
subChunk.trackers?.forEach((tracker) => {
|
this.trackers[trackerId] = {
|
||||||
if (this.data.trackers[tracker.id] === undefined) {
|
...this.trackers[trackerId],
|
||||||
this.data.trackers[tracker.id] = {};
|
...tracker,
|
||||||
}
|
};
|
||||||
this.data.trackers[tracker.id] = {
|
});
|
||||||
pos: tracker.pos,
|
}
|
||||||
speed: tracker.speed,
|
|
||||||
ori: tracker.ori,
|
|
||||||
status: tracker.status,
|
|
||||||
accel: tracker.accel,
|
|
||||||
trgtpos: tracker.trgtpos,
|
|
||||||
timestamp: tracker.timestamp,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jwetzell): add invalid frame id decoding. Scenario where a frame id is reused before one is complete
|
// TODO(jwetzell): add invalid frame id decoding. Scenario where a frame id is reused before one is complete
|
||||||
decode(packetBuf) {
|
decode(packetBuf) {
|
||||||
const packet = PacketParser.parse(packetBuf);
|
const packet = packetDecoder(packetBuf);
|
||||||
|
|
||||||
if (packet.id === 0x6756) {
|
if (packet.id === 0x6756) {
|
||||||
const infoPacket = new InfoPacket(packet);
|
const infoPacket = packet;
|
||||||
if (infoPacket) {
|
if (infoPacket) {
|
||||||
if (infoPacket.subChunks?.length > 0) {
|
if (infoPacket.has_subchunks > 0) {
|
||||||
const currentInfoPacketHeader = infoPacket.getHeaderPacket();
|
const currentInfoPacketHeader = infoPacket.packet_header;
|
||||||
if (!currentInfoPacketHeader) {
|
if (!currentInfoPacketHeader) {
|
||||||
// NOTE(jwetzell): not sure that info packets without a header subchunk are valid?
|
// NOTE(jwetzell): not sure that info packets without a header subchunk are valid?
|
||||||
return;
|
throw new Error('malformed packet');
|
||||||
}
|
}
|
||||||
|
|
||||||
const systemSubChunk = infoPacket.getSystemPacket();
|
const systemSubChunk = infoPacket.system_name;
|
||||||
if (!systemSubChunk) {
|
if (!systemSubChunk) {
|
||||||
// NOTE(jwetzell): not sure that info packets without a system subchunk are valid?
|
// NOTE(jwetzell): not sure that info packets without a system subchunk are valid?
|
||||||
return;
|
throw new Error('malformed packet');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.infoPacketFrames[currentInfoPacketHeader.frame_id] === undefined) {
|
if (this.infoPacketFrames[currentInfoPacketHeader.frame_id] === undefined) {
|
||||||
@@ -99,32 +82,27 @@ class Decoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (packet.id === 0x6755) {
|
} else if (packet.id === 0x6755) {
|
||||||
const dataPacket = new DataPacket(packet);
|
const dataPacket = packet;
|
||||||
if (dataPacket) {
|
if (dataPacket.has_subchunks) {
|
||||||
if (dataPacket.subChunks?.length > 0) {
|
const currentDataPacketHeader = dataPacket.packet_header;
|
||||||
const currentDataPacketHeader = dataPacket.getHeaderPacket();
|
if (!currentDataPacketHeader) {
|
||||||
if (!currentDataPacketHeader) {
|
// NOTE(jwetzell): not sure that info packets without a header subchunk are valid?
|
||||||
// NOTE(jwetzell): not sure that info packets without a header subchunk are valid?
|
throw new Error('malformed packet');
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.dataPacketFrames[currentDataPacketHeader.frame_id] === undefined) {
|
|
||||||
this.dataPacketFrames[currentDataPacketHeader.frame_id] = [];
|
|
||||||
}
|
|
||||||
this.dataPacketFrames[currentDataPacketHeader.frame_id].push(dataPacket);
|
|
||||||
|
|
||||||
if (
|
|
||||||
this.dataPacketFrames[currentDataPacketHeader.frame_id].length ===
|
|
||||||
currentDataPacketHeader.frame_packet_count
|
|
||||||
) {
|
|
||||||
this.updateData(this.dataPacketFrames[currentDataPacketHeader.frame_id]);
|
|
||||||
delete this.dataPacketFrames[currentDataPacketHeader.frame_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastDataPacketHeader = currentDataPacketHeader;
|
|
||||||
}
|
}
|
||||||
|
if (this.dataPacketFrames[currentDataPacketHeader.frame_id] === undefined) {
|
||||||
|
this.dataPacketFrames[currentDataPacketHeader.frame_id] = [];
|
||||||
|
}
|
||||||
|
this.dataPacketFrames[currentDataPacketHeader.frame_id].push(dataPacket);
|
||||||
|
if (
|
||||||
|
this.dataPacketFrames[currentDataPacketHeader.frame_id].length === currentDataPacketHeader.frame_packet_count
|
||||||
|
) {
|
||||||
|
this.updateData(this.dataPacketFrames[currentDataPacketHeader.frame_id]);
|
||||||
|
delete this.dataPacketFrames[currentDataPacketHeader.frame_id];
|
||||||
|
}
|
||||||
|
this.lastDataPacketHeader = currentDataPacketHeader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-19
@@ -1,20 +1,16 @@
|
|||||||
const { Parser } = require('binary-parser');
|
module.exports = (buffer, dataDecoder) => {
|
||||||
|
let offset = 0;
|
||||||
|
const chunk = {};
|
||||||
|
chunk.id = buffer.readUInt16LE(offset);
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
module.exports = new Parser()
|
// NOTE(jwetzell): this data is split up as 1 bit for has_subchunks and 15 bits for the data_len
|
||||||
.uint16le('id')
|
const combinedLengthAndFlag = buffer.readUInt16LE(offset);
|
||||||
.uint16le('data_len', {
|
chunk.has_subchunks = combinedLengthAndFlag > 32768;
|
||||||
formatter: (item) => {
|
chunk.data_len = chunk.has_subchunks ? combinedLengthAndFlag - 32768 : combinedLengthAndFlag;
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
offset += 2;
|
||||||
return Number.parseInt(binary.substring(1), 2);
|
chunk.chunk_data = buffer.subarray(offset, offset + chunk.data_len);
|
||||||
},
|
|
||||||
})
|
dataDecoder(chunk);
|
||||||
.seek(-2)
|
return chunk;
|
||||||
.uint16le('has_subchunks', {
|
};
|
||||||
formatter: (item) => {
|
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
|
||||||
return binary.charAt(0) === '1';
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.buffer('chunk_data', {
|
|
||||||
length: 'data_len',
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
const { CHUNK_HEADER_SIZE } = require('../../constants');
|
||||||
|
const chunk = require('../chunk');
|
||||||
|
const packetHeaderChunk = require('../packet-header-chunk');
|
||||||
|
const dataTrackerListChunk = require('./data-tracker-list-chunk');
|
||||||
|
|
||||||
|
function decodeDataPacketChunk(dataPacketChunk) {
|
||||||
|
if (dataPacketChunk.has_subchunks && dataPacketChunk.chunk_data) {
|
||||||
|
let offset = 0;
|
||||||
|
while (offset < dataPacketChunk.data_len) {
|
||||||
|
const chunkId = dataPacketChunk.chunk_data.readUInt16LE(offset);
|
||||||
|
switch (chunkId) {
|
||||||
|
case 0x0000:
|
||||||
|
dataPacketChunk.packet_header = packetHeaderChunk(dataPacketChunk.chunk_data.subarray(offset));
|
||||||
|
offset += CHUNK_HEADER_SIZE;
|
||||||
|
offset += dataPacketChunk.packet_header.data_len;
|
||||||
|
break;
|
||||||
|
case 0x0001:
|
||||||
|
dataPacketChunk.tracker_list = dataTrackerListChunk(dataPacketChunk.chunk_data.subarray(offset));
|
||||||
|
offset += CHUNK_HEADER_SIZE;
|
||||||
|
offset += dataPacketChunk.tracker_list.data_len;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (buffer) => chunk(buffer, decodeDataPacketChunk);
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
const { CHUNK_HEADER_SIZE } = require('../../constants');
|
||||||
|
const chunk = require('../chunk');
|
||||||
|
const dataTrackerFieldChunk = require('./data-tracker-field-chunk');
|
||||||
|
|
||||||
|
function decodeTrackerChunk(trackerChunk) {
|
||||||
|
if (trackerChunk.chunk_data && trackerChunk.data_len > 0) {
|
||||||
|
let offset = 0;
|
||||||
|
while (offset < trackerChunk.data_len) {
|
||||||
|
const trackerFieldChunk = dataTrackerFieldChunk(trackerChunk.chunk_data.subarray(offset));
|
||||||
|
offset += CHUNK_HEADER_SIZE;
|
||||||
|
offset += trackerFieldChunk.data_len;
|
||||||
|
switch (trackerFieldChunk.id) {
|
||||||
|
case 0x0000:
|
||||||
|
trackerChunk.pos = trackerFieldChunk;
|
||||||
|
break;
|
||||||
|
case 0x0001:
|
||||||
|
trackerChunk.speed = trackerFieldChunk;
|
||||||
|
break;
|
||||||
|
case 0x0002:
|
||||||
|
trackerChunk.ori = trackerFieldChunk;
|
||||||
|
break;
|
||||||
|
case 0x0003:
|
||||||
|
trackerChunk.status = trackerFieldChunk;
|
||||||
|
break;
|
||||||
|
case 0x0004:
|
||||||
|
trackerChunk.accel = trackerFieldChunk;
|
||||||
|
break;
|
||||||
|
case 0x0005:
|
||||||
|
trackerChunk.trgtpos = trackerFieldChunk;
|
||||||
|
break;
|
||||||
|
case 0x0006:
|
||||||
|
trackerChunk.timestamp = trackerFieldChunk;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (buffer) => chunk(buffer, decodeTrackerChunk);
|
||||||
@@ -1,29 +1,43 @@
|
|||||||
const Parser = require('binary-parser').Parser;
|
/* eslint-disable no-case-declarations */
|
||||||
|
const chunk = require('../chunk');
|
||||||
|
|
||||||
module.exports = new Parser()
|
function readXYZ(trackerFieldChunk, prefix) {
|
||||||
.uint16le('id')
|
if (prefix === undefined) {
|
||||||
.uint16le('data_len', {
|
prefix = '';
|
||||||
formatter: (item) => {
|
}
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
|
||||||
return Number.parseInt(binary.substring(1), 2);
|
trackerFieldChunk[`${prefix}x`] = trackerFieldChunk.chunk_data.readFloatLE(0);
|
||||||
},
|
trackerFieldChunk[`${prefix}y`] = trackerFieldChunk.chunk_data.readFloatLE(4);
|
||||||
})
|
trackerFieldChunk[`${prefix}z`] = trackerFieldChunk.chunk_data.readFloatLE(8);
|
||||||
.seek(-2)
|
}
|
||||||
.uint16le('has_subchunks', {
|
function decodeTrackerFieldChunk(trackerFieldChunk) {
|
||||||
formatter: (item) => {
|
if (trackerFieldChunk.id !== undefined) {
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
switch (trackerFieldChunk.id) {
|
||||||
return binary.charAt(0) === '1';
|
case 0x0000:
|
||||||
},
|
readXYZ(trackerFieldChunk, 'pos_');
|
||||||
})
|
break;
|
||||||
.choice('data', {
|
case 0x0001:
|
||||||
tag: 'id',
|
readXYZ(trackerFieldChunk, 'speed_');
|
||||||
choices: {
|
break;
|
||||||
0x0000: new Parser().floatle('x').floatle('y').floatle('z'),
|
case 0x0002:
|
||||||
0x0001: new Parser().floatle('x').floatle('y').floatle('z'),
|
readXYZ(trackerFieldChunk, 'ori_');
|
||||||
0x0002: new Parser().floatle('x').floatle('y').floatle('z'),
|
break;
|
||||||
0x0003: new Parser().floatle('validity'),
|
case 0x0003:
|
||||||
0x0004: new Parser().floatle('x').floatle('y').floatle('z'),
|
trackerFieldChunk.validity = trackerFieldChunk.chunk_data.readFloatLE();
|
||||||
0x0005: new Parser().floatle('x').floatle('y').floatle('z'),
|
break;
|
||||||
0x0006: new Parser().uint64le('tracker_timestamp'),
|
case 0x0004:
|
||||||
},
|
readXYZ(trackerFieldChunk, 'accel_');
|
||||||
});
|
break;
|
||||||
|
case 0x0005:
|
||||||
|
readXYZ(trackerFieldChunk, 'trgtpos_');
|
||||||
|
break;
|
||||||
|
case 0x0006:
|
||||||
|
trackerFieldChunk.tracker_timestamp = trackerFieldChunk.chunk_data.readBigUInt64LE();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (buffer) => chunk(buffer, decodeTrackerFieldChunk);
|
||||||
|
|||||||
@@ -1,24 +1,17 @@
|
|||||||
module.exports = (buffer) => {
|
const { CHUNK_HEADER_SIZE } = require('../../constants');
|
||||||
const trackerList = {
|
const chunk = require('../chunk');
|
||||||
trackers: [],
|
const dataTrackerChunk = require('./data-tracker-chunk');
|
||||||
};
|
|
||||||
|
function decodeDataTrackerListChunk(dataTrackerListChunk) {
|
||||||
|
dataTrackerListChunk.trackers = {};
|
||||||
|
|
||||||
// TODO(jwetzell): add error handling
|
// TODO(jwetzell): add error handling
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
while (offset < buffer.length) {
|
while (offset < dataTrackerListChunk.chunk_data.length) {
|
||||||
const trackerChunk = {};
|
const trackerChunk = dataTrackerChunk(dataTrackerListChunk.chunk_data.subarray(offset));
|
||||||
trackerChunk.id = buffer.readUInt16LE(offset);
|
offset += CHUNK_HEADER_SIZE;
|
||||||
offset += 2;
|
|
||||||
|
|
||||||
// NOTE(jwetzell): this data is split up as 1 bit for has_subchunks and 15 bits for the data_len
|
|
||||||
const tempBytesAsBinary = buffer.readUInt16LE(offset).toString(2);
|
|
||||||
trackerChunk.has_subchunks = tempBytesAsBinary.charAt(0) === '0';
|
|
||||||
trackerChunk.data_len = parseInt(tempBytesAsBinary.substring(1), 2);
|
|
||||||
offset += 2;
|
|
||||||
trackerChunk.data = buffer.subarray(offset, offset + trackerChunk.data_len);
|
|
||||||
offset += trackerChunk.data_len;
|
offset += trackerChunk.data_len;
|
||||||
trackerList.trackers.push(trackerChunk);
|
dataTrackerListChunk.trackers[trackerChunk.id] = trackerChunk;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return trackerList;
|
module.exports = (buffer) => chunk(buffer, decodeDataTrackerListChunk);
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
const TrackerListChunk = require('./data-tracker-list-chunk');
|
|
||||||
const TrackerFieldChunk = require('./data-tracker-field-chunk');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
TrackerFieldChunk,
|
|
||||||
TrackerListChunk,
|
|
||||||
};
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
const Chunk = require('./chunk');
|
|
||||||
const PacketHeaderChunk = require('./packet-header-chunk');
|
|
||||||
const Packet = require('./packet');
|
|
||||||
const Info = require('./info');
|
|
||||||
const Data = require('./data');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
Chunk,
|
|
||||||
PacketHeaderChunk,
|
|
||||||
Packet,
|
|
||||||
Info: {
|
|
||||||
...Info,
|
|
||||||
},
|
|
||||||
Data: {
|
|
||||||
...Data,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
const SystemNameChunk = require('./info-system-name-chunk');
|
|
||||||
const TrackerListChunk = require('./info-tracker-list-chunk');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
SystemNameChunk,
|
|
||||||
TrackerListChunk,
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
const { CHUNK_HEADER_SIZE } = require('../../constants');
|
||||||
|
const chunk = require('../chunk');
|
||||||
|
const packetHeaderChunk = require('../packet-header-chunk');
|
||||||
|
const infoSystemNameChunk = require('./info-system-name-chunk');
|
||||||
|
const infoTrackerListChunk = require('./info-tracker-list-chunk');
|
||||||
|
|
||||||
|
function decodeInfoPacketChunk(infoPacketChunk) {
|
||||||
|
if (infoPacketChunk.has_subchunks && infoPacketChunk.chunk_data) {
|
||||||
|
let offset = 0;
|
||||||
|
while (offset < infoPacketChunk.data_len) {
|
||||||
|
const chunkId = infoPacketChunk.chunk_data.readUInt16LE(offset);
|
||||||
|
switch (chunkId) {
|
||||||
|
case 0x0000:
|
||||||
|
infoPacketChunk.packet_header = packetHeaderChunk(infoPacketChunk.chunk_data.subarray(offset));
|
||||||
|
offset += CHUNK_HEADER_SIZE;
|
||||||
|
offset += infoPacketChunk.packet_header.data_len;
|
||||||
|
break;
|
||||||
|
case 0x0001:
|
||||||
|
infoPacketChunk.system_name = infoSystemNameChunk(infoPacketChunk.chunk_data.subarray(offset));
|
||||||
|
offset += CHUNK_HEADER_SIZE;
|
||||||
|
offset += infoPacketChunk.system_name.data_len;
|
||||||
|
break;
|
||||||
|
case 0x0002:
|
||||||
|
infoPacketChunk.tracker_list = infoTrackerListChunk(infoPacketChunk.chunk_data.subarray(offset));
|
||||||
|
offset += CHUNK_HEADER_SIZE;
|
||||||
|
offset += infoPacketChunk.tracker_list.data_len;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (buffer) => chunk(buffer, decodeInfoPacketChunk);
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
const Parser = require('binary-parser').Parser;
|
const chunk = require('../chunk');
|
||||||
|
|
||||||
module.exports = new Parser().string('system_name', { greedy: true });
|
function decodeSystemNameChunk(systemNameChunk) {
|
||||||
|
if (systemNameChunk.chunk_data !== undefined && systemNameChunk.data_len !== undefined) {
|
||||||
|
systemNameChunk.system_name = systemNameChunk.chunk_data.subarray(0, systemNameChunk.data_len).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (buffer) => chunk(buffer, decodeSystemNameChunk);
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
const { CHUNK_HEADER_SIZE } = require('../../constants');
|
||||||
|
const chunk = require('../chunk');
|
||||||
|
const infoTrackerNameChunk = require('./info-tracker-name-chunk');
|
||||||
|
|
||||||
|
function decodeInfoTrackerChunk(infoTrackerChunk) {
|
||||||
|
if (infoTrackerChunk.has_subchunks && infoTrackerChunk.chunk_data) {
|
||||||
|
let offset = 0;
|
||||||
|
while (offset < infoTrackerChunk.data_len) {
|
||||||
|
const chunkId = infoTrackerChunk.chunk_data.readUInt16LE(offset);
|
||||||
|
switch (chunkId) {
|
||||||
|
case 0x0000:
|
||||||
|
infoTrackerChunk.tracker_name = infoTrackerNameChunk(infoTrackerChunk.chunk_data.subarray(offset));
|
||||||
|
offset += CHUNK_HEADER_SIZE;
|
||||||
|
offset += infoTrackerChunk.tracker_name.data_len;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (buffer) => chunk(buffer, decodeInfoTrackerChunk);
|
||||||
@@ -1,39 +1,17 @@
|
|||||||
const Parser = require('binary-parser').Parser;
|
const { CHUNK_HEADER_SIZE } = require('../../constants');
|
||||||
|
const chunk = require('../chunk');
|
||||||
|
const infoTrackerChunk = require('./info-tracker-chunk');
|
||||||
|
|
||||||
const infoTrackerNameParser = new Parser()
|
function decodeInfoTrackerListChunk(infoTrackerListChunk) {
|
||||||
.uint16le('id')
|
infoTrackerListChunk.trackers = {};
|
||||||
.uint16le('data_len', {
|
if (infoTrackerListChunk.has_subchunks && infoTrackerListChunk.chunk_data) {
|
||||||
formatter: (item) => {
|
let offset = 0;
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
while (offset < infoTrackerListChunk.data_len) {
|
||||||
return Number.parseInt(binary.substring(1), 2);
|
const trackerChunk = infoTrackerChunk(infoTrackerListChunk.chunk_data.subarray(offset));
|
||||||
},
|
offset += CHUNK_HEADER_SIZE;
|
||||||
})
|
offset += trackerChunk.data_len;
|
||||||
.seek(-2)
|
infoTrackerListChunk.trackers[trackerChunk.id] = trackerChunk;
|
||||||
.uint16le('has_subchunks', {
|
}
|
||||||
formatter: (item) => {
|
}
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
}
|
||||||
return binary.charAt(0) === '1';
|
module.exports = (buffer) => chunk(buffer, decodeInfoTrackerListChunk);
|
||||||
},
|
|
||||||
})
|
|
||||||
.string('tracker_name', { length: 'data_len' });
|
|
||||||
|
|
||||||
const infoTrackerParser = new Parser()
|
|
||||||
.uint16le('id')
|
|
||||||
.uint16le('data_len', {
|
|
||||||
formatter: (item) => {
|
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
|
||||||
return Number.parseInt(binary.substring(1), 2);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.seek(-2)
|
|
||||||
.uint16le('has_subchunks', {
|
|
||||||
formatter: (item) => {
|
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
|
||||||
return binary.charAt(0) === '1';
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.nest('tracker_name', {
|
|
||||||
type: infoTrackerNameParser,
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = new Parser().array('trackers', { type: infoTrackerParser, readUntil: 'eof' });
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const chunk = require('../chunk');
|
||||||
|
|
||||||
|
function decodeTrackerNameChunk(trackerNameChunk) {
|
||||||
|
if (trackerNameChunk.chunk_data !== undefined && trackerNameChunk.data_len !== undefined) {
|
||||||
|
trackerNameChunk.tracker_name = trackerNameChunk.chunk_data.subarray(0, trackerNameChunk.data_len).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = (buffer) => chunk(buffer, decodeTrackerNameChunk);
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
const Parser = require('binary-parser').Parser;
|
const chunk = require('./chunk');
|
||||||
|
|
||||||
module.exports = new Parser()
|
function decodePacketHeaderChunk(packetHeaderChunk) {
|
||||||
.uint64le('packet_timestamp')
|
// TODO(jwetzell): remove the string conversion
|
||||||
.uint8('version_high')
|
packetHeaderChunk.packet_timestamp = packetHeaderChunk.chunk_data.readBigUInt64LE(0);
|
||||||
.uint8('version_low')
|
packetHeaderChunk.version_high = packetHeaderChunk.chunk_data.readUInt8(8);
|
||||||
.uint8('frame_id')
|
packetHeaderChunk.version_low = packetHeaderChunk.chunk_data.readUInt8(9);
|
||||||
.uint8('frame_packet_count')
|
packetHeaderChunk.frame_id = packetHeaderChunk.chunk_data.readUInt8(10);
|
||||||
.seek(4);
|
packetHeaderChunk.frame_packet_count = packetHeaderChunk.chunk_data.readUInt8(11);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (buffer) => chunk(buffer, decodePacketHeaderChunk);
|
||||||
|
|||||||
+13
-17
@@ -1,18 +1,14 @@
|
|||||||
const Parser = require('binary-parser').Parser;
|
const dataPacketChunk = require('./data/data-packet-chunk');
|
||||||
|
const infoPacketChunk = require('./info/info-packet-chunk');
|
||||||
|
|
||||||
module.exports = new Parser()
|
module.exports = (buffer) => {
|
||||||
.uint16le('id')
|
const chunkId = buffer.readUInt16LE();
|
||||||
.uint16le('data_len', {
|
switch (chunkId) {
|
||||||
formatter: (item) => {
|
case 0x6756:
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
return infoPacketChunk(buffer);
|
||||||
return Number.parseInt(binary.substring(1), 2);
|
case 0x6755:
|
||||||
},
|
return dataPacketChunk(buffer);
|
||||||
})
|
default:
|
||||||
.seek(-2)
|
return {};
|
||||||
.uint16le('has_subchunks', {
|
}
|
||||||
formatter: (item) => {
|
};
|
||||||
const binary = item.toString(2).padStart(16, '0');
|
|
||||||
return binary.charAt(0) === '1';
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.buffer('chunk_data', { readUntil: 'eof' });
|
|
||||||
|
|||||||
+16
-16
@@ -1,14 +1,13 @@
|
|||||||
const dataChunk = require('./encoders/data/data-chunk');
|
const { MAX_UDP_PACKET_SIZE, PACKET_HEADER_SIZE, CHUNK_HEADER_SIZE } = require('./constants');
|
||||||
|
const dataPacketChunk = require('./encoders/data/data-packet-chunk');
|
||||||
const dataTrackerListChunk = require('./encoders/data/data-tracker-list-chunk');
|
const dataTrackerListChunk = require('./encoders/data/data-tracker-list-chunk');
|
||||||
const infoChunk = require('./encoders/info/info-chunk');
|
const infoPacketChunk = require('./encoders/info/info-packet-chunk');
|
||||||
const infoSystemNameChunk = require('./encoders/info/info-system-name-chunk');
|
const infoSystemNameChunk = require('./encoders/info/info-system-name-chunk');
|
||||||
const infoTrackerListChunk = require('./encoders/info/info-tracker-list-chunk');
|
const infoTrackerListChunk = require('./encoders/info/info-tracker-list-chunk');
|
||||||
const packetHeaderChunk = require('./encoders/packet-header-chunk');
|
const packetHeaderChunk = require('./encoders/packet-header-chunk');
|
||||||
|
|
||||||
const MAX_TRACKER_LIST_SIZE = 1000;
|
|
||||||
|
|
||||||
class Encoder {
|
class Encoder {
|
||||||
constructor(systemName, versionHigh, versionLow) {
|
constructor(systemName, versionHigh = 2, versionLow = 3) {
|
||||||
this.systemName = systemName;
|
this.systemName = systemName;
|
||||||
this.versionHigh = versionHigh;
|
this.versionHigh = versionHigh;
|
||||||
this.versionLow = versionLow;
|
this.versionLow = versionLow;
|
||||||
@@ -17,6 +16,8 @@ class Encoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getInfoPackets(timestamp, trackers) {
|
getInfoPackets(timestamp, trackers) {
|
||||||
|
const systemNameChunk = infoSystemNameChunk(this.systemName);
|
||||||
|
|
||||||
const trackerChunks = trackers.map((tracker) => tracker.getInfoChunk());
|
const trackerChunks = trackers.map((tracker) => tracker.getInfoChunk());
|
||||||
|
|
||||||
const infoPackets = [];
|
const infoPackets = [];
|
||||||
@@ -24,16 +25,16 @@ class Encoder {
|
|||||||
const trackerChunksLists = [];
|
const trackerChunksLists = [];
|
||||||
let currentTrackerList = [];
|
let currentTrackerList = [];
|
||||||
|
|
||||||
let currentTrackerListSize = 0;
|
let currentInfoPacketSize = PACKET_HEADER_SIZE + systemNameChunk.length + CHUNK_HEADER_SIZE;
|
||||||
|
|
||||||
trackerChunks.forEach((trackerChunk) => {
|
trackerChunks.forEach((trackerChunk) => {
|
||||||
if (currentTrackerListSize + trackerChunk.length > MAX_TRACKER_LIST_SIZE) {
|
if (currentInfoPacketSize + trackerChunk.length > MAX_UDP_PACKET_SIZE) {
|
||||||
trackerChunksLists.push(currentTrackerList);
|
trackerChunksLists.push(currentTrackerList);
|
||||||
currentTrackerList = [];
|
currentTrackerList = [];
|
||||||
currentTrackerListSize = 0;
|
currentInfoPacketSize = 0;
|
||||||
}
|
}
|
||||||
currentTrackerList.push(trackerChunk);
|
currentTrackerList.push(trackerChunk);
|
||||||
currentTrackerListSize += trackerChunk.length;
|
currentInfoPacketSize += trackerChunk.length;
|
||||||
});
|
});
|
||||||
trackerChunksLists.push(currentTrackerList);
|
trackerChunksLists.push(currentTrackerList);
|
||||||
const header = packetHeaderChunk(
|
const header = packetHeaderChunk(
|
||||||
@@ -44,7 +45,7 @@ class Encoder {
|
|||||||
trackerChunksLists.length
|
trackerChunksLists.length
|
||||||
);
|
);
|
||||||
trackerChunksLists.forEach((trackerChunkList) => {
|
trackerChunksLists.forEach((trackerChunkList) => {
|
||||||
infoPackets.push(infoChunk(header, infoSystemNameChunk(this.systemName), infoTrackerListChunk(trackerChunkList)));
|
infoPackets.push(infoPacketChunk(header, systemNameChunk, infoTrackerListChunk(trackerChunkList)));
|
||||||
});
|
});
|
||||||
this.dataFrameId += 1;
|
this.dataFrameId += 1;
|
||||||
if (this.dataFrameId > 255) {
|
if (this.dataFrameId > 255) {
|
||||||
@@ -55,22 +56,21 @@ class Encoder {
|
|||||||
|
|
||||||
getDataPackets(timestamp, trackers) {
|
getDataPackets(timestamp, trackers) {
|
||||||
const allTrackerChunks = trackers.map((tracker) => tracker.getDataChunk());
|
const allTrackerChunks = trackers.map((tracker) => tracker.getDataChunk());
|
||||||
|
|
||||||
const dataPackets = [];
|
const dataPackets = [];
|
||||||
|
|
||||||
const trackerChunksLists = [];
|
const trackerChunksLists = [];
|
||||||
let currentTrackerList = [];
|
let currentTrackerList = [];
|
||||||
|
|
||||||
let currentTrackerListSize = 0;
|
let currentDataPacketSize = PACKET_HEADER_SIZE + CHUNK_HEADER_SIZE;
|
||||||
|
|
||||||
allTrackerChunks.forEach((trackerChunk) => {
|
allTrackerChunks.forEach((trackerChunk) => {
|
||||||
if (currentTrackerListSize + trackerChunk.length > MAX_TRACKER_LIST_SIZE) {
|
if (currentDataPacketSize + trackerChunk.length > MAX_UDP_PACKET_SIZE) {
|
||||||
trackerChunksLists.push(currentTrackerList);
|
trackerChunksLists.push(currentTrackerList);
|
||||||
currentTrackerList = [];
|
currentTrackerList = [];
|
||||||
currentTrackerListSize = 0;
|
currentDataPacketSize = 0;
|
||||||
}
|
}
|
||||||
currentTrackerList.push(trackerChunk);
|
currentTrackerList.push(trackerChunk);
|
||||||
currentTrackerListSize += trackerChunk.length;
|
currentDataPacketSize += trackerChunk.length;
|
||||||
});
|
});
|
||||||
trackerChunksLists.push(currentTrackerList);
|
trackerChunksLists.push(currentTrackerList);
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ class Encoder {
|
|||||||
trackerChunksLists.length
|
trackerChunksLists.length
|
||||||
);
|
);
|
||||||
trackerChunksLists.forEach((trackerChunks) => {
|
trackerChunksLists.forEach((trackerChunks) => {
|
||||||
dataPackets.push(dataChunk(header, dataTrackerListChunk(trackerChunks)));
|
dataPackets.push(dataPacketChunk(header, dataTrackerListChunk(trackerChunks)));
|
||||||
});
|
});
|
||||||
this.dataFrameId += 1;
|
this.dataFrameId += 1;
|
||||||
if (this.dataFrameId > 255) {
|
if (this.dataFrameId > 255) {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
const chunk = require('../chunk');
|
const chunk = require('../chunk');
|
||||||
|
|
||||||
module.exports = (trackerId, fieldChunks) => chunk(trackerId, Buffer.concat(fieldChunks), true);
|
module.exports = (trackerId, fieldChunks) => chunk(trackerId, Buffer.concat(fieldChunks), fieldChunks.length > 0);
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ const chunk = require('../chunk');
|
|||||||
|
|
||||||
module.exports = (timestamp) => {
|
module.exports = (timestamp) => {
|
||||||
const buf = Buffer.alloc(8);
|
const buf = Buffer.alloc(8);
|
||||||
const timestampHigh = timestamp.toString(2).padStart(64, '0').substring(0, 32);
|
buf.writeBigUInt64LE(BigInt(timestamp));
|
||||||
const timestampLow = timestamp.toString(2).padStart(64, '0').substring(32);
|
|
||||||
buf.writeUInt32LE(parseInt(timestampLow, 2));
|
|
||||||
buf.writeUInt32LE(parseInt(timestampHigh, 2), 4);
|
|
||||||
return chunk(0x0006, buf, false);
|
return chunk(0x0006, buf, false);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,11 +5,7 @@ module.exports = (timestamp, versionHigh, versionLow, frameId, framePacketCount)
|
|||||||
throw new Error('frame id must be >= 0 and <= 255');
|
throw new Error('frame id must be >= 0 and <= 255');
|
||||||
}
|
}
|
||||||
const packetHeader = Buffer.alloc(12);
|
const packetHeader = Buffer.alloc(12);
|
||||||
const timestampHigh = timestamp.toString(2).padStart(64, '0').substring(0, 32);
|
packetHeader.writeBigUInt64LE(BigInt(timestamp));
|
||||||
const timestampLow = timestamp.toString(2).padStart(64, '0').substring(32);
|
|
||||||
packetHeader.writeUInt32LE(parseInt(timestampLow, 2));
|
|
||||||
packetHeader.writeUInt32LE(parseInt(timestampHigh, 2), 4);
|
|
||||||
|
|
||||||
packetHeader.writeUint8(versionHigh, 8);
|
packetHeader.writeUint8(versionHigh, 8);
|
||||||
packetHeader.writeUint8(versionLow, 9);
|
packetHeader.writeUint8(versionLow, 9);
|
||||||
packetHeader.writeUint8(frameId, 10);
|
packetHeader.writeUint8(frameId, 10);
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
/* eslint-disable no-case-declarations */
|
|
||||||
/* eslint-disable no-param-reassign */
|
|
||||||
const { Parser } = require('binary-parser');
|
|
||||||
const Decoders = require('../../decoders');
|
|
||||||
|
|
||||||
class DataPacket {
|
|
||||||
constructor(packet) {
|
|
||||||
this.packet = packet;
|
|
||||||
this.subChunks = [];
|
|
||||||
// console.log(this.packet);
|
|
||||||
if (this.packet.has_subchunks) {
|
|
||||||
this.subChunkParser = new Parser().array('chunks', {
|
|
||||||
type: Decoders.Chunk,
|
|
||||||
lengthInBytes: this.packet.data_len,
|
|
||||||
});
|
|
||||||
this.subChunks = this.subChunkParser.parse(this.packet.chunk_data)?.chunks;
|
|
||||||
this.subChunks = this.subChunks.map((subChunk) => {
|
|
||||||
let populatedSubChunk = {};
|
|
||||||
populatedSubChunk.data_len_valid = subChunk.chunk_data.length === subChunk.data_len;
|
|
||||||
switch (subChunk.id) {
|
|
||||||
case 0:
|
|
||||||
populatedSubChunk = {
|
|
||||||
...subChunk,
|
|
||||||
...Decoders.PacketHeaderChunk.parse(subChunk.chunk_data),
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
const dataTrackerList = Decoders.Data.TrackerListChunk(subChunk.chunk_data);
|
|
||||||
dataTrackerList.trackers?.forEach((tracker) => {
|
|
||||||
if (tracker.data && tracker.data_len > 0) {
|
|
||||||
const fields = new Parser()
|
|
||||||
.array('fields', {
|
|
||||||
type: Decoders.Data.TrackerFieldChunk,
|
|
||||||
lengthInBytes: tracker.data_len,
|
|
||||||
})
|
|
||||||
.parse(tracker.data);
|
|
||||||
if (fields.fields) {
|
|
||||||
fields.fields.forEach((field) => {
|
|
||||||
switch (field.id) {
|
|
||||||
case 0x0000:
|
|
||||||
tracker.pos = field.data;
|
|
||||||
break;
|
|
||||||
case 0x0001:
|
|
||||||
tracker.speed = field.data;
|
|
||||||
break;
|
|
||||||
case 0x0002:
|
|
||||||
tracker.ori = field.data;
|
|
||||||
break;
|
|
||||||
case 0x0003:
|
|
||||||
tracker.status = field.data;
|
|
||||||
break;
|
|
||||||
case 0x0004:
|
|
||||||
tracker.accel = field.data;
|
|
||||||
break;
|
|
||||||
case 0x0005:
|
|
||||||
tracker.trgtpos = field.data;
|
|
||||||
break;
|
|
||||||
case 0x0006:
|
|
||||||
tracker.timestamp = field.data;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
populatedSubChunk = {
|
|
||||||
...subChunk,
|
|
||||||
...dataTrackerList,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
populatedSubChunk = {
|
|
||||||
...subChunk,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return populatedSubChunk;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getHeaderPacket() {
|
|
||||||
return this.subChunks.find((subChunk) => subChunk.id === 0x0000);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSystemPacket() {
|
|
||||||
return this.subChunks.find((subChunk) => subChunk.id === 0x0001);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = DataPacket;
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
const DataPacket = require('./data-packet');
|
|
||||||
const InfoPacket = require('./info-packet');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
DataPacket,
|
|
||||||
InfoPacket,
|
|
||||||
};
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
const { Parser } = require('binary-parser');
|
|
||||||
const Decoders = require('../../decoders');
|
|
||||||
|
|
||||||
class InfoPacket {
|
|
||||||
constructor(packet) {
|
|
||||||
this.packet = packet;
|
|
||||||
this.subChunks = [];
|
|
||||||
if (this.packet.has_subchunks) {
|
|
||||||
this.subChunkParser = new Parser().array('chunks', {
|
|
||||||
type: Decoders.Chunk,
|
|
||||||
lengthInBytes: this.packet.data_len,
|
|
||||||
});
|
|
||||||
this.subChunks = this.subChunkParser.parse(this.packet.chunk_data)?.chunks;
|
|
||||||
this.subChunks = this.subChunks.map((subChunk) => {
|
|
||||||
let populatedSubChunk = {};
|
|
||||||
populatedSubChunk.data_len_valid = subChunk.chunk_data.length === subChunk.data_len;
|
|
||||||
switch (subChunk.id) {
|
|
||||||
case 0:
|
|
||||||
populatedSubChunk = {
|
|
||||||
...subChunk,
|
|
||||||
...Decoders.PacketHeaderChunk.parse(subChunk.chunk_data),
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
populatedSubChunk = {
|
|
||||||
...subChunk,
|
|
||||||
...Decoders.Info.SystemNameChunk.parse(subChunk.chunk_data),
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
populatedSubChunk = {
|
|
||||||
...subChunk,
|
|
||||||
...Decoders.Info.TrackerListChunk.parse(subChunk.chunk_data),
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
populatedSubChunk = {
|
|
||||||
...subChunk,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return populatedSubChunk;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getHeaderPacket() {
|
|
||||||
return this.subChunks.find((subChunk) => subChunk.id === 0x0000);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSystemPacket() {
|
|
||||||
return this.subChunks.find((subChunk) => subChunk.id === 0x0001);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = InfoPacket;
|
|
||||||
Reference in New Issue
Block a user