Skip to content

ryangibbs/spacepackets

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

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors