The tmsc package implements the CCSDS 131.0-B-4 TM Synchronization and Channel Coding sublayer — the layer between the TM Data Link Protocol and the physical link that handles frame synchronization, pseudo-randomization, and forward error correction.
import "github.com/ravisuhag/astro/pkg/tmsc"
// Wrap a Transfer Frame into a CADU for transmission
cadu := tmsc.WrapCADU(encodedFrame, nil, true) // nil=default ASM, true=randomize
// Unwrap a received CADU back into a Transfer Frame
frameData, err := tmsc.UnwrapCADU(cadu, nil, true)
// Reed-Solomon error correction
rs := tmsc.NewRS255_223()
codeword, _ := rs.Encode(data)
corrected, nerrs, _ := rs.Decode(codeword)The TMSC sublayer sits between the TM Data Link Protocol (tmdl) and the physical layer:
+-----------------------------------------+
| TM Space Data Link Protocol (tmdl) |
| Packs data into Transfer Frames |
+-----------------------------------------+
| TM Sync & Channel Coding (tmsc) | <-- This package
| ASM, pseudo-randomization, FEC |
+-----------------------------------------+
| Physical Layer (RF/Optical link) |
+-----------------------------------------+
The ASM is a known 4-byte bit pattern prepended to each Transfer Frame. The receiver uses it to find frame boundaries in the continuous bitstream.
// Get the standard CCSDS ASM (0x1ACFFC1D)
asm := tmsc.DefaultASM() // Returns []byte{0x1A, 0xCF, 0xFC, 0x1D}The ASM was carefully chosen for its autocorrelation properties — it can be detected reliably even in the presence of noise. A fresh copy is returned each call to prevent accidental mutation.
A Channel Access Data Unit (CADU) is the combination of ASM + Transfer Frame data. This is the unit that is actually transmitted over the physical link.
+--------+------------------------+
| ASM | Transfer Frame |
| (4B) | |
+--------+------------------------+
|<------------ CADU ------------->|
// Wrap with default ASM and pseudo-randomization
cadu := tmsc.WrapCADU(encodedFrame, nil, true)
// Wrap with default ASM, no randomization
cadu := tmsc.WrapCADU(encodedFrame, nil, false)
// Wrap with custom ASM
customASM := []byte{0xDE, 0xAD, 0xBE, 0xEF}
cadu := tmsc.WrapCADU(encodedFrame, customASM, true)// Unwrap with default ASM and de-randomization
frameData, err := tmsc.UnwrapCADU(cadu, nil, true)
if errors.Is(err, tmsc.ErrSyncMarkerMismatch) {
// ASM not found at expected position
}
// Unwrap without de-randomization
frameData, err := tmsc.UnwrapCADU(cadu, nil, false)CCSDS pseudo-randomization ensures good signal properties by preventing long runs of identical bits that can confuse clock recovery. The Transfer Frame bytes are XORed with a pseudo-random noise (PN) sequence.
// Randomize data (XOR with PN sequence)
randomized := tmsc.Randomize(data)
// De-randomize (same operation — XOR is self-inverse)
original := tmsc.Randomize(randomized)The PN sequence is generated by an 8-bit LFSR with polynomial h(x) = x^8 + x^7 + x^5 + x^3 + 1, initialized to all 1s (0xFF).
// Generate PN sequence of arbitrary length
pnSeq := tmsc.GeneratePNSequence(1024)Important: The ASM is never randomized. Only the Transfer Frame content is XORed.
The package provides CCSDS Reed-Solomon codes over GF(2^8) with primitive polynomial 0x187 and first consecutive root (FCR) 112.
| Code | Parity Symbols | Error Correction | Use Case |
|---|---|---|---|
| RS(255,223) | 32 | Up to 16 errors | Standard CCSDS coding |
| RS(255,239) | 16 | Up to 8 errors | Lower overhead alternative |
// Create a codec
rs := tmsc.NewRS255_223() // or tmsc.NewRS255_239()
// Encode: data (223 bytes) -> codeword (255 bytes)
data := make([]byte, rs.DataLen()) // 223 bytes for RS(255,223)
codeword, err := rs.Encode(data)
// Decode: corrects errors in-place, returns corrected data
corrected, numErrors, err := rs.Decode(codeword)
if errors.Is(err, tmsc.ErrUncorrectable) {
// Too many errors to correct
}
fmt.Printf("Corrected %d symbol errors\n", numErrors)CCSDS supports symbol interleaving to spread burst errors across multiple codewords, improving resilience against clustered bit errors.
Valid interleave depths: 1, 2, 3, 4, 5, 8.
rs := tmsc.NewRS255_223()
depth := 4
// Input must be exactly depth * DataLen() bytes
data := make([]byte, depth*rs.DataLen()) // 4 * 223 = 892 bytes
interleaved, err := rs.EncodeInterleaved(data, depth)
// Output: depth * 255 = 1020 bytes
// Decode interleaved data
corrected, totalErrors, err := rs.DecodeInterleaved(interleaved, depth)How interleaving works:
- Input data is de-interleaved into
depthseparate blocks. - Each block is independently RS-encoded to a 255-byte codeword.
- The codewords are interleaved byte-by-byte into the output.
On decode, the reverse is performed. This means a burst error affecting consecutive bytes in the interleaved stream is distributed across multiple codewords, where each codeword sees only a few symbol errors.
rs := tmsc.NewRS255_223()
rs.NRoots() // 32 — number of parity symbols
rs.DataLen() // 223 — data bytes per codewordimport (
"github.com/ravisuhag/astro/pkg/tmdl"
"github.com/ravisuhag/astro/pkg/tmsc"
)
// 1. Get a Transfer Frame from the TM Data Link layer
frame, _ := pc.GetNextFrame()
encoded, _ := frame.Encode()
// 2. (Optional) Apply Reed-Solomon encoding
rs := tmsc.NewRS255_223()
// Pad encoded frame to RS data length if needed, or use interleaving
// 3. Wrap as CADU — randomize and prepend ASM
cadu := tmsc.WrapCADU(encoded, nil, true)
// 4. Transmit CADU over the physical link
transmit(cadu)// 1. Receive CADU from physical link
cadu := receive()
// 2. Unwrap CADU — strip ASM and de-randomize
frameData, err := tmsc.UnwrapCADU(cadu, nil, true)
if err != nil { /* handle sync errors */ }
// 3. (Optional) Apply Reed-Solomon decoding/correction
// 4. Decode the Transfer Frame
frame, err := tmdl.DecodeTMTransferFrame(frameData)
if err != nil { /* handle CRC errors */ }All errors are exported package-level variables, suitable for use with errors.Is:
| Error | Meaning |
|---|---|
ErrDataTooShort |
CADU too short to contain the ASM |
ErrSyncMarkerMismatch |
CADU does not start with the expected ASM |
ErrInvalidDataLength |
Data length does not match RS code parameters |
ErrInvalidInterleaveDepth |
Unsupported interleaving depth (must be 1, 2, 3, 4, 5, or 8) |
ErrUncorrectable |
Errors exceed RS correction capability |
- CCSDS 131.0-B-5 — TM Synchronization and Channel Coding Blue Book
- CCSDS 130.1-G-3 — TM Synchronization and Channel Coding Summary (Green Book)
tmdlpackage — TM Space Data Link Protocol