You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
5.0 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpacePacketParser = void 0;
const stream_1 = require("stream");
const utils_1 = require("./utils");
/**
* A Transform stream that accepts a stream of octet data and converts it into an object
* representation of a CCSDS Space Packet. See https://public.ccsds.org/Pubs/133x0b2e1.pdf for a
* description of the Space Packet format.
*/
class SpacePacketParser extends stream_1.Transform {
/**
* A Transform stream that accepts a stream of octet data and emits object representations of
* CCSDS Space Packets once a packet has been completely received.
* @param {Object} [options] Configuration options for the stream
* @param {Number} options.timeCodeFieldLength The length of the time code field within the data
* @param {Number} options.ancillaryDataFieldLength The length of the ancillary data field within the data
*/
constructor(options = {}) {
super({ ...options, objectMode: true });
// Set the constants for this Space Packet Connection; these will help us parse incoming data
// fields:
this.timeCodeFieldLength = options.timeCodeFieldLength || 0;
this.ancillaryDataFieldLength = options.ancillaryDataFieldLength || 0;
this.dataSlice = this.timeCodeFieldLength + this.ancillaryDataFieldLength;
// These are stateful based on the current packet being received:
this.dataBuffer = Buffer.alloc(0);
this.headerBuffer = Buffer.alloc(0);
this.dataLength = 0;
this.expectingHeader = true;
}
/**
* Bundle the header, secondary header if present, and the data into a JavaScript object to emit.
* If more data has been received past the current packet, begin the process of parsing the next
* packet(s).
*/
pushCompletedPacket() {
if (!this.header) {
throw new Error('Missing header');
}
const timeCode = Buffer.from(this.dataBuffer.slice(0, this.timeCodeFieldLength));
const ancillaryData = Buffer.from(this.dataBuffer.slice(this.timeCodeFieldLength, this.timeCodeFieldLength + this.ancillaryDataFieldLength));
const data = Buffer.from(this.dataBuffer.slice(this.dataSlice, this.dataLength));
const completedPacket = {
header: { ...this.header },
data: data.toString(),
};
if (timeCode.length > 0 || ancillaryData.length > 0) {
completedPacket.secondaryHeader = {};
if (timeCode.length) {
completedPacket.secondaryHeader.timeCode = timeCode.toString();
}
if (ancillaryData.length) {
completedPacket.secondaryHeader.ancillaryData = ancillaryData.toString();
}
}
this.push(completedPacket);
// If there is an overflow (i.e. we have more data than the packet we just pushed) begin parsing
// the next packet.
const nextChunk = Buffer.from(this.dataBuffer.slice(this.dataLength));
if (nextChunk.length >= utils_1.HEADER_LENGTH) {
this.extractHeader(nextChunk);
}
else {
this.headerBuffer = nextChunk;
this.dataBuffer = Buffer.alloc(0);
this.expectingHeader = true;
this.dataLength = 0;
this.header = undefined;
}
}
/**
* Build the Stream's headerBuffer property from the received Buffer chunk; extract data from it
* if it's complete. If there's more to the chunk than just the header, initiate handling the
* packet data.
* @param chunk - Build the Stream's headerBuffer property from
*/
extractHeader(chunk) {
const headerAsBuffer = Buffer.concat([this.headerBuffer, chunk]);
const startOfDataBuffer = headerAsBuffer.slice(utils_1.HEADER_LENGTH);
if (headerAsBuffer.length >= utils_1.HEADER_LENGTH) {
this.header = (0, utils_1.convertHeaderBufferToObj)(headerAsBuffer);
this.dataLength = this.header.dataLength;
this.headerBuffer = Buffer.alloc(0);
this.expectingHeader = false;
}
else {
this.headerBuffer = headerAsBuffer;
}
if (startOfDataBuffer.length > 0) {
this.dataBuffer = Buffer.from(startOfDataBuffer);
if (this.dataBuffer.length >= this.dataLength) {
this.pushCompletedPacket();
}
}
}
_transform(chunk, encoding, cb) {
if (this.expectingHeader) {
this.extractHeader(chunk);
}
else {
this.dataBuffer = Buffer.concat([this.dataBuffer, chunk]);
if (this.dataBuffer.length >= this.dataLength) {
this.pushCompletedPacket();
}
}
cb();
}
_flush(cb) {
const remaining = Buffer.concat([this.headerBuffer, this.dataBuffer]);
const remainingArray = Array.from(remaining);
this.push(remainingArray);
cb();
}
}
exports.SpacePacketParser = SpacePacketParser;