Skip to content

Repository files navigation

spacepackets

spacepackets

CI

A TypeScript library for encoding and decoding CCSDS Space Packets — the standard packet format used in spacecraft telemetry and telecommand systems (CCSDS 133.0-B-2).

Install

npm install @onion-party/spacepackets
# or
pnpm add @onion-party/spacepackets

Quick start

Decode a telemetry packet

import { decode, PacketType } from "@onion-party/spacepackets";

const bytes = new Uint8Array([/* raw packet bytes from socket or file */]);
const packet = decode(bytes);

console.log(packet.header.apid);          // Application Process ID
console.log(packet.header.sequenceCount); // For gap detection
console.log(packet.header.packetType);    // PacketType.Telemetry or PacketType.Telecommand
console.log(packet.dataField);            // Uint8Array — secondary header + user data

Encode a telecommand

import { encode, PacketType, SequenceFlags } from "@onion-party/spacepackets";

const packet = {
  header: {
    packetVersionNumber: 0,
    packetType: PacketType.Telecommand,
    secondaryHeaderFlag: false,
    apid: 100,
    sequenceFlags: SequenceFlags.Standalone,
    sequenceCount: 0,
    dataLength: 2, // dataField.byteLength - 1
  },
  dataField: new Uint8Array([0x01, 0x02, 0x03]),
};

const bytes = encode(packet); // Uint8Array ready for transmission

Assemble packets from a byte stream

Packets often arrive in chunks — split across frame boundaries or delivered over a socket. PacketAssembler buffers incoming bytes and emits complete packets.

import { PacketAssembler } from "@onion-party/spacepackets";

const assembler = new PacketAssembler();

// Feed raw bytes as they arrive (e.g. from a UDP socket)
socket.on("data", (chunk: Buffer) => {
  const packets = assembler.onChunk(chunk);
  for (const packet of packets) {
    console.log("received packet", packet.header.apid);
  }
});

Full pipeline (Node.js streams)

All three stream classes compose via .pipe() for a fully declarative receive pipeline:

import {
  PacketAssemblerStream,
  GapDetectorStream,
  SegmentationReassemblerStream,
  type ReassembledAdu,
} from "@onion-party/spacepackets";

socket
  .pipe(new PacketAssemblerStream({ maxBufferBytes: 1_000_000 }))
  .pipe(new GapDetectorStream({
    onGap: (gap) => console.warn(`APID ${gap.apid}: ${gap.missing} packet(s) missing`),
  }))
  .pipe(new SegmentationReassemblerStream({
    onError: (err) => console.warn(`APID ${err.apid}: ${err.kind}`),
  }))
  .on("data", (adu: ReassembledAdu) => {
    console.log(`APID ${adu.apid}: ${adu.data.byteLength} bytes`);
  });

Detect gaps in the packet stream

GapDetector tracks the sequence count per APID and fires a callback whenever packets are missing.

import { GapDetector, PacketAssembler } from "@onion-party/spacepackets";

const assembler = new PacketAssembler();
const detector = new GapDetector({
  onGap: (gap) => {
    console.warn(`APID ${gap.apid}: expected ${gap.expected}, got ${gap.received}${gap.missing} packet(s) missing`);
  },
});

socket.on("data", (chunk: Buffer) => {
  const packets = assembler.onChunk(chunk);
  for (const packet of packets) {
    detector.onPacket(packet.header);
  }
});

Reassemble segmented ADUs

Large application data units (ADUs) are sometimes split across multiple packets using First/Continuation/Last sequence flags. SegmentationReassembler buffers segments per APID and emits the fully concatenated data when the final segment arrives.

import { PacketAssembler, SegmentationReassembler } from "@onion-party/spacepackets";

const assembler = new PacketAssembler();
const reassembler = new SegmentationReassembler({
  onAdu: (adu) => {
    console.log(`APID ${adu.apid}: reassembled ${adu.data.byteLength} bytes`);
  },
  onError: (err) => {
    if (err.kind === 'ORPHANED_SEGMENT') {
      console.warn(`APID ${err.apid}: segment arrived with no matching First packet`);
    } else {
      console.warn(`APID ${err.apid}: new First arrived while ADU was in-progress — abandoned`);
    }
  },
});

socket.on("data", (chunk: Buffer) => {
  const packets = assembler.onChunk(chunk);
  for (const packet of packets) {
    reassembler.onPacket(packet);
  }
});

Error handling

All errors thrown by this library are instances of SpacePacketError. Use the code field to branch programmatically without parsing message strings.

import { decode, SpacePacketError } from "@onion-party/spacepackets";

try {
  const packet = decode(bytes);
} catch (err) {
  if (err instanceof SpacePacketError) {
    switch (err.code) {
      case "BUFFER_TOO_SHORT":
        // Not enough bytes yet — wait for more data
        break;
      case "INVALID_VERSION":
        // Packet version number is non-zero — malformed or unsupported
        break;
    }
  }
}

API

Functions

Function Description
encode(packet) Serialize a SpacePacket to a Uint8Array
decode(bytes) Parse a Uint8Array into a SpacePacket
decodeHeader(bytes) Parse only the 6-byte primary header — useful in streaming contexts to learn the full packet length before the payload has arrived
getPacketLength(header) Returns the total byte length of a packet given its header (6 + header.dataLength + 1)
isIdlePacket(header) Returns true if the packet's APID is 0x7FF (the reserved idle/fill APID); idle packets carry no mission data and should be discarded

Classes

Class Description
PacketAssembler Stateful buffer that accepts raw byte chunks via onChunk(chunk) and returns complete SpacePacket[]. Handles packets split across chunk boundaries.
GapDetector Tracks sequence counts per APID and calls onGap whenever packets are missing. Handles 14-bit wrap-around and ignores idle packets.
SegmentationReassembler Reassembles segmented ADUs from First/Continuation/Last packet sequences. Calls onAdu when complete, onError on out-of-order or orphaned segments.
PacketAssemblerStream Node.js Transform stream wrapping PacketAssembler. Accepts raw byte chunks on the writable side, emits decoded SpacePacket objects on the readable side. Emits INCOMPLETE_PACKET if the stream ends mid-packet.
GapDetectorStream Passthrough Transform stream wrapping GapDetector. Accepts and re-emits SpacePacket objects; calls onGap as a side effect for any detected sequence gaps.
SegmentationReassemblerStream Transform stream wrapping SegmentationReassembler. Accepts SpacePacket objects, emits ReassembledAdu objects when a complete ADU is assembled.
SpacePacketError Thrown by encode/decode on malformed input, or emitted by PacketAssemblerStream. Has a code field: BUFFER_TOO_SHORT, INVALID_VERSION, APID_OUT_OF_RANGE, DATA_FIELD_EMPTY, DATA_LENGTH_MISMATCH, SEQUENCE_COUNT_OUT_OF_RANGE, PACKET_TOO_LARGE, BUFFER_OVERFLOW, INCOMPLETE_PACKET.

Specification

This library implements CCSDS 133.0-B-2 — Space Packet Protocol, published by the Consultative Committee for Space Data Systems (CCSDS).

License

MIT

About

Encode and decode CCSDS Space Packets for ground station and spacecraft software.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages