ccsds-spp
v0.1.0
Published
CSDS Space Packet Protocol implementation for Node.js
Maintainers
Readme
CCSDS SPP: Space Packet Protocol for Node.js
Overview
CCSDS SPP is a comprehensive Node.js library that implements the Consultative Committee for Space Data Systems (CCSDS) Space Packet Protocol (SPP). This implementation provides tools for encoding, transmitting, receiving, and decoding spacecraft telemetry and command packets according to the international CCSDS-133.0-B-2 standard. The library enables satellite ground stations, mission control centers, and space-based systems to reliably exchange structured data over multiple transport protocols while maintaining full compliance with space industry standards.
What is Space Packet Protocol?
The Space Packet Protocol is an international standard used by space agencies worldwide to structure telemetry and command data exchanged with spacecraft. It defines a common format for packaging data with essential metadata including:
- APID (Application Process Identifier): Identifies the originating or destination application, depending on individual mission configuration (0-2047)
- Packet Type: Distinguishes between telemetry (TM) and telecommand (TC) packets
- Sequence Flags: Enables reassembly of segmented packets
- Packet Counting: Tracks packet ordering and detects losses
- Optional Secondary Headers: Support for time codes and ancillary data
The protocol is widely adopted by space organizations including NASA, ESA, JAXA, and ISRO for deep space missions, Earth observation satellites, and the International Space Station.
Key Features
Multi-Transport Support
The library seamlessly handles four different transport mechanisms:
- TCP: Reliable, connection-oriented communication
- UDP: Low-latency, connectionless protocol
- WebSocket: Browser-compatible transport for web-based mission control interfaces
- MQTT: IoT-friendly publish-subscribe model for distributed systems
Each transport is independently configurable and can be selected via configuration file or command-line arguments.
Packet Segmentation & Reassembly
Large transfer datasets that exceed the packet size limits are automatically divided into smaller packets and marked with sequence flags. The library handles reassembly transparently:
- Unsegmented packets: Single self-contained packets (sequence flag = 3)
- Segmented packets: Multi-packet messages with start (flag 1), continuation (flag 0), and end (flag 2) markers
- Out-of-order handling: Packets may arrive out-of-order; the library buffers and reassembles intelligently
- Automatic extraction mode: Optionally reassemble packets on the receive side before processing
Multiple Time Code Standards
The library implements four CCSDS time code formats, each optionally using the preamble byte, to support mission requirements:
- CDS (CCSDS Day Segmented):
CDS: 6 bytes (16-bit day, 32-bit millisecond)CDS_P: 7 bytes (includes preamble byte)
- CCS (CCSDS Segmented):
CCS_DAY: 9 bytes (day-of-year format)CCS_DAY_P: 10 bytes (with preamble)CCS_MON: 9 bytes (month/day-of-month format)CCS_MON_P: 10 bytes (with preamble)
- ASCII Time Code:
ASCII: 24 bytes (human-readable ASCII format:YYYY-MM-DDThh:mm:ss.dddZ)ASCII_P: 24 bytes (same as ASCII; preamble argument ignored)
When using these optional format flags, time codes will be automatically generated when packets are sent, and inserted correctly into the secondary header.
Protocol Wrapping
For advanced use cases, SPP packets can be wrapped with additional framing protocols:
- AX.25: Amateur radio packet format, commonly used in cubesat and educational missions
- KISS (Keep It Simple, Stupid): Serial line framing protocol for radio modem interfaces
Both wrappers add necessary framing while maintaining SPP compliance.
Type-Safe API
Built entirely in TypeScript, the library provides:
- Full type definitions exported for integration with type-safe applications
- Strict validation of packet structure and parameters
- Compile-time checking of configuration objects
Installation
npm install ccsds-sppOr with yarn:
yarn add ccsds-sppQuick Start
Basic Usage: Sending Telemetry
import SpacePacketProtocol, { UDPTX } from 'ccsds-spp';
// Create a UDP transport
const transport = new UDPTX({
transport: 'udp',
version: 'udp4',
remoteAddress: 'localhost',
remotePort: 5000,
localPort: 5001
});
// Create SPP instance
const spp = new SpacePacketProtocol({
tx: transport,
extract: false // Don't extract on receive; get raw packets
});
// Send telemetry from APID 100
const userData = JSON.stringify({
apid: 100,
packetType: 'TM',
userData: 'Hello from spacecraft'
});
spp.write(userData);
// Receive packets
spp.on('data', (packet) => {
console.log('Received packet:', packet);
});With Time Codes
// Send telemetry with automatic timestamp
const telemWithTime = JSON.stringify({
apid: 200,
packetType: 'TELEMETRY',
userData: 'Temperature: 25.3C',
timeCodeFn: 'CDS' // Automatic Unix Epoch timestamp
});
spp.write(telemWithTime);TCP Transport with Configuration File
Create mission-config.json:
{
"transport": "tcp",
"host": "mission-control.example.com",
"port": 5000
}In your application:
import SpacePacketProtocol, { TCPTX } from 'ccsds-spp';
import * as fs from 'node:fs/promises';
const config = JSON.parse(
await fs.readFile('mission-config.json', 'utf8')
);
const tcpTransport = new TCPTX(config);
const spp = new SpacePacketProtocol({ tx: tcpTransport });
// Use as normal
spp.write(JSON.stringify({
apid: 300,
packetType: 'TC',
userData: 'Execute command 42'
}));Command Packets
// Send telecommand (packet type = 1)
const command = JSON.stringify({
apid: 50,
packetType: 'TC', // or 'TELECOMMAND' or 1
userData: 'POWER_ON_HEATER'
});
spp.write(command);Extraction Mode: Automatic Reassembly
const spp = new SpacePacketProtocol({
tx: myTransport,
extract: true // Automatically reassemble segmented packets
});
spp.on('data', (extractedPacket) => {
// Packet is reassembled even if it arrived segmented
console.log('APID:', extractedPacket.apid);
console.log('Assembled from', extractedPacket.assembledPackets, 'segments');
console.log('User data:', extractedPacket.userDataRaw);
});Advanced: AX.25 Wrapping for Amateur Radio
{
"transport": "udp",
"version": "udp4",
"remoteAddress": "192.168.1.100",
"remotePort": 4000,
"localPort": 4000,
"ax25": true,
"myCall": "W5XYZ",
"remoteCall": "N0CALL",
"layer3": "NO_LAYER_3_PROTOCOL",
"useFlags": true
}The AX.25 wrapper automatically frames all SPP packets with amateur radio protocol overhead, enabling transmission over radio modems and repeater networks.
MQTT Transport for Distributed Systems
{
"transport": "mqtt",
"url": "mqtt://broker.example.com:1883",
"sendTopic": "spacecraft/telemetry",
"recvTopic": "mission-control/commands",
"mqttUsername": "operator",
"mqttPassword": "secure-password"
}This configuration publishes all outgoing SPP packets to an MQTT topic and subscribes to receive incoming commands, enabling multi-client mission control architectures.
API Reference
SpacePacketProtocol (Main Class)
Constructor
new SpacePacketProtocol(init: SpacePacketProtocolInitArgs)Parameters:
txor{xmit, recv}: Transport stream(s) for sending and receivingextract(optional): Enable automatic packet reassembly (default: false)decoding(optional): Buffer encoding for userDataEnc field (e.g., 'utf8', 'hex')maxPDSize(optional): Maximum packet data size in bytes (default: 65536)timeCodeFn(optional): Default time code function name for secondary headers
Methods
write(chunk: string | Buffer): void
Sends a packet. Input can be a JSON string representing a UserPacket or a Buffer.
on('data', callback: (packet: SpacePacket | ExtractedSpacePacket) => void): void
Listens for received packets. Emits either raw SpacePacket (extract=false) or ExtractedSpacePacket (extract=true) objects.
UserPacket (Input Format)
interface UserPacket {
apid: number; // 0-2047
packetType: 'TM' | 'TC' | // Telemetry or Telecommand
'TELEMETRY' | 'TELECOMMAND' |
0 | 1;
userData?: string; // Payload data (base64 or string)
timeCodeFn?: TimeCodeKey; // Optional: CDS, CDS_P, CCS_DAY, etc.
ancillaryData?: string; // Optional: secondary header data
dataEncoding?: 'utf8' | 'hex' | // Input encoding for userData
'base64' | ...;
}SpacePacket (Output Format)
interface SpacePacket {
apid: number;
packetId: string; // Hex-formatted packet ID (e.g., "0x1a2b")
rawPacketId: number;
version: number; // SPP version (always 1 for CCSDS)
packetType: 'TELEM' | 'COMMAND';
packetDataLength: number;
userDataRaw: string; // Hex-encoded payload
userDataEnc?: string; // Optional decoded data (if decoding set)
fullPacketRaw: string; // Hex-encoded entire packet
secondaryHeader: boolean;
sequenceFlag: 0 | 1 | 2 | 3; // 0=continuation, 1=start, 2=end, 3=unsegmented
}ExtractedSpacePacket (Reassembled Output)
interface ExtractedSpacePacket {
apid: number;
version: number;
firstPacketId: string;
rawFirstPacketId: number;
assembledPackets: number; // Number of segments merged
packetType: 'TELEM' | 'COMMAND';
userDataRaw: string; // Complete payload
userDataEnc?: string;
secondaryHeader: boolean;
}Command-Line Interface
A CLI tool is available in apps/command-line/app.ts for development and testing. Supported options include:
-c, --conf <path>: Load configuration from JSON file-t, --transport <mqtt|tcp|udp|ws>: Transport type-u, --url <url>: Remote host URL/IP-p, --port <number>: Remote host port--lp, --local-port <number>: Local port--lh, --local-host <url>: Local host URL/IP--un, --user-name <string>: Username (for MQTT)--up, --user-password <string>: Password (for MQTT)--wk, --wrap-kiss: Enable KISS framing--wx, --wrap-ax25: Enable AX.25 framing
The CLI accepts JSON on stdin and writes received packets to stdout.
Real-World Examples
Example 1: Ground Station Receiver
import SpacePacketProtocol, { TCPTX } from 'ccsds-spp';
import * as fs from 'node:fs';
const spp = new SpacePacketProtocol({
tx: new TCPTX({
transport: 'tcp',
host: '192.168.1.1',
port: 9000
}),
extract: true, // Reassemble segmented packets
decoding: 'utf8'
});
spp.on('data', (packet) => {
const timestamp = new Date().toISOString();
const log = `[${timestamp}] APID=${packet.apid} Data=${packet.userDataEnc}\n`;
fs.appendFileSync('telemetry.log', log);
});Example 2: Spacecraft Command Handler
import SpacePacketProtocol, { UDPTX } from 'ccsds-spp';
const spp = new SpacePacketProtocol({
tx: new UDPTX({
transport: 'udp',
version: 'udp4',
remoteAddress: 'spacecraft.local',
remotePort: 10000,
localPort: 10000
}),
timeCodeFn: 'CDS' // All packets include timestamp
});
// Send commands with time code
spp.write(JSON.stringify({
apid: 1,
packetType: 'TC',
userData: 'RTC_SYNC',
timeCodeFn: 'CDS'
}));Example 3: Integration with TypeScript
import SpacePacketProtocol, {
type SpacePacket,
MAX_APID
} from 'ccsds-spp';
const spp = new SpacePacketProtocol({ tx: transport });
function handlePacket(packet: SpacePacket) {
if (packet.apid >= 0 && packet.apid < MAX_APID) {
const payload = Buffer.from(packet.userDataRaw, 'hex');
console.log(`Got ${payload.length} bytes from APID ${packet.apid}`);
}
}
spp.on('data', handlePacket);Configuration Schema
The library includes a JSON schema (transport-config.json) for validating configuration files in IDEs and build tools. Use it for autocomplete and validation:
{
"$schema": "./schemata/transport-config.json",
"transport": "tcp",
"host": "example.com",
"port": 5000
}Performance Considerations
- Packet Size: The library supports packets up to 65,536 bytes of data. Configure
maxPDSizeto match your transport MTU (e.g., 1500 for Ethernet). - Extraction Overhead: Packet reassembly requires in-memory buffering. For high-volume, real-time telemetry, consider disabling extraction and handling segmentation at the application layer.
Standards Compliance
This implementation conforms to:
- CCSDS 133.0-B-2: Space Packet Protocol
- CCSDS 301.0-B-4: CCSDS Time Code Formats
License
ISC
Contributing
Contributions are welcome. Please ensure code includes type definitions and follows the existing style.
