1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright (c) 2026 G & R Associates LLC
// SPDX-License-Identifier: MIT OR Apache-2.0
// src/waveform/dvb_t_ts.rs
//
// DVB-T MPEG-2 transport-stream (TS) payload adaptation and energy dispersal,
// ETSI EN 300 744 §4.3.1. Real (NB-)DVB-T carries a genuine 188-byte MPEG-2 TS —
// this module models that packet structure so the DVB-T pipeline ingests TS
// packets rather than opaque bytes, applying the standard's exact
// energy-dispersal rules that key off packet boundaries:
//
// • Packets are 188 bytes: one sync byte (0x47) + 187 payload bytes.
// • The PRBS (1 + X^14 + X^15, init 100101010000000) re-initializes at the
// start of every group of EIGHT packets.
// • The sync byte of the FIRST packet in each group is inverted 0x47 → 0xB8
// (the descrambler's re-init signal). The other seven packets keep 0x47.
// • Sync bytes are NOT randomized, but the PRBS generator keeps clocking over
// them (8 steps, output discarded) so the register phase stays aligned; the
// 187 payload bytes of every packet ARE randomized.
//
// This wraps the Phase-1 `DvbTEnergyDispersal` whitener (which is the bit-exact
// PRBS) with the packet framing. The RS(204,188) outer code then protects each
// randomized 188-byte packet (sync byte included) — one TS packet is exactly one
// RS information block, which is why the payload FEC needs no stuffing.
use cratedvb_tDvbTEnergyDispersal;
/// MPEG-2 transport-stream packet length in bytes (1 sync + 187 payload).
pub const TS_PACKET_LEN: usize = 188;
/// Number of payload bytes per TS packet (all but the sync byte).
pub const TS_PAYLOAD_LEN: usize = TS_PACKET_LEN - 1;
/// The MPEG-2 sync byte (`0x47`).
pub const TS_SYNC_BYTE: u8 = 0x47;
/// The inverted sync byte (`0xB8`) marking the first packet of an 8-packet group.
pub const TS_SYNC_BYTE_INVERTED: u8 = 0xB8;
/// Number of TS packets per energy-dispersal group (PRBS re-init period).
pub const TS_DISPERSAL_GROUP: usize = 8;
/// Applies (or inverts) DVB-T energy dispersal over a whole number of 188-byte TS
/// packets, in place. Self-inverse: running scrambled packets through again
/// recovers the originals, because the sync-byte inversion is deterministic per
/// group position and the PRBS is the same data-independent sequence.
///
/// `packets` must be a multiple of [`TS_PACKET_LEN`] bytes and each packet must
/// begin with a sync byte (`0x47` or its inverted form `0xB8`). Per the standard:
/// the PRBS re-inits every 8 packets, the first packet of each group has its sync
/// byte inverted, and the PRBS clocks over every sync byte without randomizing
/// it. Returns the number of packets processed.
///
/// # Panics
///
/// Panics if `packets.len()` is not a multiple of [`TS_PACKET_LEN`].
/// Wraps arbitrary payload bytes into whole TS packets (sync byte + 187 payload),
/// zero-padding the final packet's payload. This is a minimal TS adaptation for
/// the library's own end-to-end use (not a full MPEG-2 multiplexer): every packet
/// gets a plain `0x47` sync byte; `ts_energy_disperse` later inverts the
/// group-leading ones. Returns the packetized byte stream (a multiple of
/// [`TS_PACKET_LEN`]).
/// A single MPEG-2 **null packet** (PID `0x1FFF`), the standard TS stuffing
/// packet. Header: sync `0x47`, then PID bits all 1 with a payload-only
/// adaptation field control; the 184 payload bytes are `0xFF` (§4.3.1 keeps the
/// data stream continuous — a compliant modulator emits null packets rather than
/// nothing when there is no program data). The 4-byte header is
/// `47 1F FF 10`: PID 0x1FFF split across bytes 1–2 (`0x1F`/`0xFF`), byte 3 =
/// `0x10` (adaptation_field_control = 01, payload only, continuity counter 0).
/// Appends whole null TS packets to an already-packetized `ts` byte stream until
/// it reaches at least `target_packets` packets, so the coded stream fills the
/// OFDM frame instead of leaving zeroed data carriers (§4.4: every symbol carries
/// data). `ts` must already be a whole number of `TS_PACKET_LEN`-byte packets; a
/// no-op if it already holds `target_packets` or more.
/// Recovers the payload bytes from whole TS packets (inverse of [`ts_packetize`]):
/// strips each packet's sync byte and concatenates the 187-byte payloads. The
/// caller trims trailing zero padding via the known original length. Returns
/// `None` if `packets` is not a whole number of TS packets.