Astro~/0.3
** Docs / Getting started / Quickstart, CLI * PAGE 03 / 27
** Astro * Docs
** /docs/start/quickstart-cli

Quickstart, CLI

Encode, inspect, and validate packets from a terminal.

The astro command reads and writes CCSDS data on stdin and stdout, so you can pipe it. Everything below is real output.

Make a packet

astro spp encode --apid 100 --type tm --data 68656c6c6f
0064c000000468656c6c6f

That is a Space Packet carrying the five bytes hello, from application 100. Hex out by default; --format bin gives you raw bytes.

Look inside one

astro spp encode --apid 100 --type tm --data 68656c6c6f | astro spp inspect --input hex
Space Packet Inspector
────────────────────────────────────────────────────────────
Primary Header (6 bytes)
  Version .............. 0
  Type ................. 0 (TM)
  Secondary Header Flag  0
  APID ................. 100 (0x064)
  Sequence Flags ....... 3 (unsegmented)
  Sequence Count ....... 0
  Packet Data Length ... 4 (total packet: 11 bytes)
────────────────────────────────────────────────────────────
User Data (5 bytes)
  0000  68 65 6c 6c 6f                                    |hello|
────────────────────────────────────────────────────────────
Raw Packet (11 bytes)
  0000  00 64 c0 00 00 04 68 65  6c 6c 6f                 |.d....hello|

inspect is the one you want when staring at a capture. It shows the raw field value and what it means, note Packet Data Length reads 4 for a five-byte payload, because that field is length minus one.

Check a CRC

astro spp encode --apid 100 --type tm --data a1b2c3d4 --crc | astro spp validate --input hex --crc
Packet is valid.
  Type: TM, APID: 100, SeqCount: 0, Data: 4 bytes
  CRC: 0x6956 (OK)

Both sides need --crc. Without it on the decode side, the two CRC bytes come back as payload.

Get JSON out

Every decode command takes --format json, so you can pipe into jq:

astro spp encode --apid 100 --type tm --data 68656c6c6f \
  | astro spp decode --input hex --format json
{
  "version": 0,
  "type": 0,
  "type_name": "TM",
  "secondary_header_flag": 0,
  "apid": 100,
  "sequence_flags": 3,
  "sequence_flags_name": "unsegmented",
  "sequence_count": 0,
  "packet_length": 4,
  "user_data": "68656c6c6f",
  "is_idle": false
}

Build a whole chain

Packet into a TM frame, frame into a CADU:

PKT=$(astro spp encode --apid 100 --type tm --data 68656c6c6f)
FRAME=$(astro tm encode --scid 42 --vcid 0 --data "$PKT")
echo "$FRAME" | astro cadu wrap --input hex
1acffc1d02a0000018000064c000000468656c6c6f7629

The 1acffc1d on the front is the Attached Sync Marker. Unwrap it again with astro cadu unwrap.

Time codes

astro time now
Current UTC: 2026-09-01T03:47:32.798716Z
────────────────────────────────────────────────────────────
CUC .... 1e8128a979cc78
CDS .... 4061f800d0533e
CCS .... 5a202602440347327987
ASCII-A  2026-09-01T03:47:32.798Z
ASCII-B  2026-244T03:47:32.798Z

Four time code formats, same instant. astro time decode reads any of them back.

Generate test data

astro spp gen --apid 100 --count 10 --size 64 --format hex

Useful for feeding a receiver you are writing. astro tm gen and astro cadu gen do the same at their layers.

Manual pages

Every command's full reference is built into the binary:

astro manual spp
astro manual        # list the topics