fast-ccsds-parser
Fast, dependency-free parsing of CCSDS Space Packets (CCSDS 133.0-B-2)
for the modern Python data stack. Turn raw telemetry dumps into dicts and
structured objects in one pass: primary headers, packet boundaries, and
payloads, with a pure standard-library core that installs anywhere
(pip install and go).
Built for small-satellite teams, university labs, and data engineers who just want their packets parsed, without pulling a decoding framework.
Install
pip install fast-ccsds-parser
or from source:
pip install git+https://github.com/daikiito-dk/fast-ccsds-parser.git
Quickstart
from fast_ccsds_parser import parse_primary_header, iter_file
# One header, as a plain dict:
header = parse_primary_header(raw_bytes)
# {'version': 0, 'type': 0, 'secondary_header_flag': 1, 'apid': 42,
# 'sequence_flags': 3, 'sequence_count': 1337, 'packet_length': 255}
# A whole ground-station dump, streamed packet by packet (constant memory):
for pkt in iter_file("dump_20261010.pkts"):
print(pkt.header.apid, pkt.header.sequence_count, len(pkt.payload))
# In-memory buffers work the same way:
packets = [p.to_dict() for p in iter_packets(buffer)]
What it parses
The 6-byte CCSDS primary header (all fields big-endian):
bit: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0-1 | version | T | S | APID |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2-3 | seq flags | sequence count / packet name |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
4-5 | packet length |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| Field | Bits | Meaning |
|---|---|---|
version |
3 | 0 for space packets |
type |
1 | 0 = telemetry, 1 = telecommand |
secondary_header_flag |
1 | 1 = a secondary header follows the primary header |
apid |
11 | application process identifier (all ones = idle) |
sequence_flags |
2 | segmentation status (unsegmented = 0b11) |
sequence_count |
14 | packet sequence count / packet name |
packet_length |
16 | data field length minus one (see below) |
API
| Entry point | Purpose |
|---|---|
parse_primary_header(data, *, offset=0, strict=True) |
Header fields as a dict |
PrimaryHeader.from_bytes(data, *, offset=0, strict=True) |
Header as a NamedTuple (.apid, .total_length, .is_idle, .to_dict(), ...) |
parse_packet(data, *, strict=True) |
Exactly one packet, as a SpacePacket |
iter_packets(data, *, strict=True, skip_idle=False) |
Generator over a buffer of concatenated packets |
parse_packets(data, ...) |
Same, as a list |
iter_file(path, ...) / parse_file(path, ...) |
Stream packets from a dump file with O(1) memory |
SpacePacket carries header (a PrimaryHeader), payload (the data
field bytes), raw (the complete packet bytes), and a to_dict() that
flattens everything into a single dict.
Semantics to know
packet_lengthis zero-based. The data field ispacket_length + 1bytes, so a total packet is6 + packet_length + 1bytes. This is the number-one source of off-by-one bugs when handling CCSDS data, and the parser handles it for you.payload= the full data field. Per CCSDS 133.0-B-2 the data field is an optional secondary header followed by user data; the payload bytes are returned as-is. Checkheader.has_secondary_headerto know whether a mission-specific secondary header is in front. Decoding those layouts is out of scope for the structural parser (see the roadmap).- Idle packets (APID =
0x7FF) are yielded like any other packet by default; passskip_idle=Trueto filter them out. - Strict mode (default) raises
InvalidPacketErrorwhen the packet version is not 0, which usually means your byte stream is misaligned. Passstrict=Falseto parse anyway. - All errors derive from
FastCCSDSError(aValueError).
Positioning
| fast-ccsds-parser | ccsdspy | space-packet-parser | |
|---|---|---|---|
| Focus | Structural parsing: split and label packets, fast | Field-level decoding from packet definitions | Field-level decoding from XTCE definitions |
| Runtime dependencies | None | Yes | Yes |
| DataFrame / stream pipelines | Roadmap (Phase 2) | - | - |
If you need to decode packet contents against a mission packet database, look at ccsdspy or space-packet-parser; both are excellent and battle tested. fast-ccsds-parser does one thing: fast, dependency-free structural parsing that is trivial to drop into a pandas or asyncio pipeline.
Performance & roadmap
The Phase 1 core is a single-pass parser over precompiled struct layouts
and integer bit operations, and streams files with constant memory, so
megabyte- to gigabyte-scale dumps are handled without surprises.
- Phase 2 (v0.2):
to_dataframe()(optionalpandasextra) and asyncio generators for live TCP socket / WebSocket streams (optionalwebsocketextra). - Phase 3: replace the core hot loop with Rust (PyO3), keeping the Python API unchanged.
Development
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest # offline test suite
ruff check . # lint
Tests marked network additionally parse public, real-world packet dumps
downloaded on the fly; they skip automatically when offline (CI runs them).
Releasing (PyPI)
Publishing uses trusted publishing (no API tokens). One-time setup is
described in .github/workflows/publish-testpypi.yml
(the file name is historical; it publishes to PyPI). Bump __version__ in
src/fast_ccsds_parser/__init__.py, add a CHANGELOG entry, then:
git tag vX.Y.Z
git push origin vX.Y.Z
The workflow builds sdist + wheel, runs twine check, and uploads to
PyPI.
License
Metadata
Release files for fast-ccsds-parser 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fast_ccsds_parser-0.1.0.tar.gz | 19.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fast_ccsds_parser-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.7 kB
Release files / fast_ccsds_parser-0.1.0.tar.gz
| Download URL | fast_ccsds_parser-0.1.0.tar.gz |
|---|---|
| Size | 19.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a3eee6dd281f2852d62b5ae8e1792a2be696df9b19227a91c04382813bc3bf6f
|
|
BLAKE2b-256 checksum How to use checksums |
76886c8836e8eb41d0e8c3726eb0b5f82d6ddb3e2e9dc489d49de7f80f4aa259
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency logRelease files / fast_ccsds_parser-0.1.0-py3-none-any.whl
| Download URL | fast_ccsds_parser-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
452fd78226721543d34692cd7b7249f19b58ecf6ef9be9ba8e084df6f5cc3f34
|
|
BLAKE2b-256 checksum How to use checksums |
ee54f56162b18a201302f6cfaf7877e71ff0247f2b4882466b13d8828966fe5e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency log