Skip to main content

dvb_simulcrypt/
registry.rs

1//! Interface scoping + the message_type / parameter_type / error_status value
2//! registries for the two implemented SimulCrypt interfaces.
3//!
4//! ETSI TS 103 197 V1.5.1 — Table 2 (protocol_version, §4.4.1 p. 27),
5//! Table 3 (message_type, §4.4.1 pp. 27-28), Table 5/6 (ECMG⇔SCS parameter /
6//! error, §5.2/§5.6) and Table 7/8 (EMMG/PDG⇔MUX parameter / error,
7//! §6.2.2/§6.2.6).
8//!
9//! The `message_type` numeric space is **interface-scoped**: the same 16-bit
10//! value means different things on different interfaces (and on the wire the
11//! interface is fixed by which TCP connection the message arrived on — this
12//! crate takes it as the [`Interface`] hint to [`crate::SimulcryptMessage::parse_on`]).
13
14/// The SimulCrypt connection-oriented interface a message belongs to.
15///
16/// Only the two head-end CA interfaces are implemented; the remaining
17/// TS 103 197 interfaces (C(P)SIG⇔(P)SIG, EIS⇔SCS, (P)SIG⇔MUX, ACG⇔EIS,
18/// SIMCOMP⇔MUXCONFIG) share the same framing but are not modelled here.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize))]
21#[non_exhaustive]
22pub enum Interface {
23    /// ECMG ⇔ SCS (TS 103 197 clause 5).
24    EcmgScs,
25    /// EMMG/PDG ⇔ MUX (TS 103 197 clause 6).
26    EmmgPdgMux,
27}
28
29impl Interface {
30    /// The mandated `protocol_version` byte for this interface (Table 2).
31    ///
32    /// Both implemented interfaces use `0x03` (the `0x05` DVB-H variant of
33    /// annex N is not modelled).
34    pub const PROTOCOL_VERSION: u8 = 0x03;
35
36    /// `protocol_version` for this interface (Table 2, §4.4.1 p. 27).
37    #[must_use]
38    pub const fn protocol_version(self) -> u8 {
39        match self {
40            Self::EcmgScs | Self::EmmgPdgMux => Self::PROTOCOL_VERSION,
41        }
42    }
43
44    /// Label per the project's `name()` convention.
45    #[must_use]
46    pub fn name(&self) -> &'static str {
47        match self {
48            Self::EcmgScs => "ECMG<->SCS",
49            Self::EmmgPdgMux => "EMMG/PDG<->MUX",
50        }
51    }
52}
53dvb_common::impl_spec_display!(Interface);
54
55// ===========================================================================
56// message_type — ECMG ⇔ SCS (Table 3 subset, §5)
57// ===========================================================================
58
59/// ECMG⇔SCS `message_type` values (TS 103 197 Table 3, §4.4.1 pp. 27-28).
60///
61/// `Reserved(u16)` is the catch-all for any value outside the registry
62/// (DVB-reserved or user-defined); it preserves the raw 16-bit value so
63/// `Display`/serialize stay lossless.
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize))]
66#[non_exhaustive]
67pub enum EcmgScsMessageType {
68    /// `0x0001` channel_setup.
69    ChannelSetup,
70    /// `0x0002` channel_test.
71    ChannelTest,
72    /// `0x0003` channel_status.
73    ChannelStatus,
74    /// `0x0004` channel_close.
75    ChannelClose,
76    /// `0x0005` channel_error.
77    ChannelError,
78    /// `0x0101` stream_setup.
79    StreamSetup,
80    /// `0x0102` stream_test.
81    StreamTest,
82    /// `0x0103` stream_status.
83    StreamStatus,
84    /// `0x0104` stream_close_request.
85    StreamCloseRequest,
86    /// `0x0105` stream_close_response.
87    StreamCloseResponse,
88    /// `0x0106` stream_error.
89    StreamError,
90    /// `0x0201` CW_provision.
91    CwProvision,
92    /// `0x0202` ECM_response.
93    EcmResponse,
94    /// Any value not in the ECMG⇔SCS registry (DVB-reserved / user-defined).
95    Reserved(u16),
96}
97
98impl EcmgScsMessageType {
99    /// Decode a 16-bit `message_type` for the ECMG⇔SCS interface.
100    #[must_use]
101    pub const fn from_u16(v: u16) -> Self {
102        match v {
103            0x0001 => Self::ChannelSetup,
104            0x0002 => Self::ChannelTest,
105            0x0003 => Self::ChannelStatus,
106            0x0004 => Self::ChannelClose,
107            0x0005 => Self::ChannelError,
108            0x0101 => Self::StreamSetup,
109            0x0102 => Self::StreamTest,
110            0x0103 => Self::StreamStatus,
111            0x0104 => Self::StreamCloseRequest,
112            0x0105 => Self::StreamCloseResponse,
113            0x0106 => Self::StreamError,
114            0x0201 => Self::CwProvision,
115            0x0202 => Self::EcmResponse,
116            other => Self::Reserved(other),
117        }
118    }
119
120    /// The 16-bit wire value.
121    #[must_use]
122    pub const fn to_u16(self) -> u16 {
123        match self {
124            Self::ChannelSetup => 0x0001,
125            Self::ChannelTest => 0x0002,
126            Self::ChannelStatus => 0x0003,
127            Self::ChannelClose => 0x0004,
128            Self::ChannelError => 0x0005,
129            Self::StreamSetup => 0x0101,
130            Self::StreamTest => 0x0102,
131            Self::StreamStatus => 0x0103,
132            Self::StreamCloseRequest => 0x0104,
133            Self::StreamCloseResponse => 0x0105,
134            Self::StreamError => 0x0106,
135            Self::CwProvision => 0x0201,
136            Self::EcmResponse => 0x0202,
137            Self::Reserved(v) => v,
138        }
139    }
140
141    /// Label per the project's `name()` convention.
142    #[must_use]
143    pub fn name(&self) -> &'static str {
144        match self {
145            Self::ChannelSetup => "channel_setup",
146            Self::ChannelTest => "channel_test",
147            Self::ChannelStatus => "channel_status",
148            Self::ChannelClose => "channel_close",
149            Self::ChannelError => "channel_error",
150            Self::StreamSetup => "stream_setup",
151            Self::StreamTest => "stream_test",
152            Self::StreamStatus => "stream_status",
153            Self::StreamCloseRequest => "stream_close_request",
154            Self::StreamCloseResponse => "stream_close_response",
155            Self::StreamError => "stream_error",
156            Self::CwProvision => "CW_provision",
157            Self::EcmResponse => "ECM_response",
158            Self::Reserved(_) => "reserved",
159        }
160    }
161}
162dvb_common::impl_spec_display!(EcmgScsMessageType, Reserved);
163
164// ===========================================================================
165// message_type — EMMG/PDG ⇔ MUX (Table 3 subset, §6)
166// ===========================================================================
167
168/// EMMG/PDG⇔MUX `message_type` values (TS 103 197 Table 3, §4.4.1 pp. 27-28).
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
170#[cfg_attr(feature = "serde", derive(serde::Serialize))]
171#[non_exhaustive]
172pub enum EmmgMuxMessageType {
173    /// `0x0011` channel_setup.
174    ChannelSetup,
175    /// `0x0012` channel_test.
176    ChannelTest,
177    /// `0x0013` channel_status.
178    ChannelStatus,
179    /// `0x0014` channel_close.
180    ChannelClose,
181    /// `0x0015` channel_error.
182    ChannelError,
183    /// `0x0111` stream_setup.
184    StreamSetup,
185    /// `0x0112` stream_test.
186    StreamTest,
187    /// `0x0113` stream_status.
188    StreamStatus,
189    /// `0x0114` stream_close_request.
190    StreamCloseRequest,
191    /// `0x0115` stream_close_response.
192    StreamCloseResponse,
193    /// `0x0116` stream_error.
194    StreamError,
195    /// `0x0117` stream_BW_request.
196    StreamBwRequest,
197    /// `0x0118` stream_BW_allocation.
198    StreamBwAllocation,
199    /// `0x0211` data_provision.
200    DataProvision,
201    /// Any value not in the EMMG/PDG⇔MUX registry (DVB-reserved / user-defined).
202    Reserved(u16),
203}
204
205impl EmmgMuxMessageType {
206    /// Decode a 16-bit `message_type` for the EMMG/PDG⇔MUX interface.
207    #[must_use]
208    pub const fn from_u16(v: u16) -> Self {
209        match v {
210            0x0011 => Self::ChannelSetup,
211            0x0012 => Self::ChannelTest,
212            0x0013 => Self::ChannelStatus,
213            0x0014 => Self::ChannelClose,
214            0x0015 => Self::ChannelError,
215            0x0111 => Self::StreamSetup,
216            0x0112 => Self::StreamTest,
217            0x0113 => Self::StreamStatus,
218            0x0114 => Self::StreamCloseRequest,
219            0x0115 => Self::StreamCloseResponse,
220            0x0116 => Self::StreamError,
221            0x0117 => Self::StreamBwRequest,
222            0x0118 => Self::StreamBwAllocation,
223            0x0211 => Self::DataProvision,
224            other => Self::Reserved(other),
225        }
226    }
227
228    /// The 16-bit wire value.
229    #[must_use]
230    pub const fn to_u16(self) -> u16 {
231        match self {
232            Self::ChannelSetup => 0x0011,
233            Self::ChannelTest => 0x0012,
234            Self::ChannelStatus => 0x0013,
235            Self::ChannelClose => 0x0014,
236            Self::ChannelError => 0x0015,
237            Self::StreamSetup => 0x0111,
238            Self::StreamTest => 0x0112,
239            Self::StreamStatus => 0x0113,
240            Self::StreamCloseRequest => 0x0114,
241            Self::StreamCloseResponse => 0x0115,
242            Self::StreamError => 0x0116,
243            Self::StreamBwRequest => 0x0117,
244            Self::StreamBwAllocation => 0x0118,
245            Self::DataProvision => 0x0211,
246            Self::Reserved(v) => v,
247        }
248    }
249
250    /// Label per the project's `name()` convention.
251    #[must_use]
252    pub fn name(&self) -> &'static str {
253        match self {
254            Self::ChannelSetup => "channel_setup",
255            Self::ChannelTest => "channel_test",
256            Self::ChannelStatus => "channel_status",
257            Self::ChannelClose => "channel_close",
258            Self::ChannelError => "channel_error",
259            Self::StreamSetup => "stream_setup",
260            Self::StreamTest => "stream_test",
261            Self::StreamStatus => "stream_status",
262            Self::StreamCloseRequest => "stream_close_request",
263            Self::StreamCloseResponse => "stream_close_response",
264            Self::StreamError => "stream_error",
265            Self::StreamBwRequest => "stream_BW_request",
266            Self::StreamBwAllocation => "stream_BW_allocation",
267            Self::DataProvision => "data_provision",
268            Self::Reserved(_) => "reserved",
269        }
270    }
271}
272dvb_common::impl_spec_display!(EmmgMuxMessageType, Reserved);
273
274/// Interface-tagged `message_type`: decode a raw value once the [`Interface`]
275/// is known.
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
277#[cfg_attr(feature = "serde", derive(serde::Serialize))]
278#[non_exhaustive]
279pub enum MessageType {
280    /// An ECMG⇔SCS message_type.
281    EcmgScs(EcmgScsMessageType),
282    /// An EMMG/PDG⇔MUX message_type.
283    EmmgPdgMux(EmmgMuxMessageType),
284}
285
286impl MessageType {
287    /// Decode a raw 16-bit `message_type` for the given interface.
288    #[must_use]
289    pub const fn from_u16(iface: Interface, v: u16) -> Self {
290        match iface {
291            Interface::EcmgScs => Self::EcmgScs(EcmgScsMessageType::from_u16(v)),
292            Interface::EmmgPdgMux => Self::EmmgPdgMux(EmmgMuxMessageType::from_u16(v)),
293        }
294    }
295
296    /// The 16-bit wire value.
297    #[must_use]
298    pub const fn to_u16(self) -> u16 {
299        match self {
300            Self::EcmgScs(m) => m.to_u16(),
301            Self::EmmgPdgMux(m) => m.to_u16(),
302        }
303    }
304
305    /// The interface this message_type was decoded against.
306    #[must_use]
307    pub const fn interface(self) -> Interface {
308        match self {
309            Self::EcmgScs(_) => Interface::EcmgScs,
310            Self::EmmgPdgMux(_) => Interface::EmmgPdgMux,
311        }
312    }
313
314    /// Label per the project's `name()` convention.
315    #[must_use]
316    pub fn name(&self) -> &'static str {
317        match self {
318            Self::EcmgScs(m) => m.name(),
319            Self::EmmgPdgMux(m) => m.name(),
320        }
321    }
322}
323dvb_common::impl_spec_display!(MessageType);
324
325// ===========================================================================
326// parameter_type — ECMG ⇔ SCS (Table 5, §5.2 p. 31)
327// ===========================================================================
328
329/// ECMG⇔SCS `parameter_type` values (TS 103 197 Table 5, §5.2 p. 31).
330#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
331#[cfg_attr(feature = "serde", derive(serde::Serialize))]
332#[non_exhaustive]
333pub enum EcmgScsParameterType {
334    /// `0x0001` Super_CAS_id (uimsbf, 4 bytes).
335    SuperCasId,
336    /// `0x0002` section_TSpkt_flag (uimsbf, 1 byte).
337    SectionTspktFlag,
338    /// `0x0003` delay_start (tcimsbf/ms, 2 bytes).
339    DelayStart,
340    /// `0x0004` delay_stop (tcimsbf/ms, 2 bytes).
341    DelayStop,
342    /// `0x0005` transition_delay_start (tcimsbf/ms, 2 bytes).
343    TransitionDelayStart,
344    /// `0x0006` transition_delay_stop (tcimsbf/ms, 2 bytes).
345    TransitionDelayStop,
346    /// `0x0007` ECM_rep_period (uimsbf/ms, 2 bytes).
347    EcmRepPeriod,
348    /// `0x0008` max_streams (uimsbf, 2 bytes).
349    MaxStreams,
350    /// `0x0009` min_CP_duration (uimsbf/n×100ms, 2 bytes).
351    MinCpDuration,
352    /// `0x000A` lead_CW (uimsbf, 1 byte).
353    LeadCw,
354    /// `0x000B` CW_per_msg (uimsbf, 1 byte).
355    CwPerMsg,
356    /// `0x000C` max_comp_time (uimsbf/ms, 2 bytes).
357    MaxCompTime,
358    /// `0x000D` access_criteria (user defined, variable).
359    AccessCriteria,
360    /// `0x000E` ECM_channel_id (uimsbf, 2 bytes).
361    EcmChannelId,
362    /// `0x000F` ECM_stream_id (uimsbf, 2 bytes).
363    EcmStreamId,
364    /// `0x0010` nominal_CP_duration (uimsbf/n×100ms, 2 bytes).
365    NominalCpDuration,
366    /// `0x0011` access_criteria_transfer_mode (Boolean, 1 byte).
367    AccessCriteriaTransferMode,
368    /// `0x0012` CP_number (uimsbf, 2 bytes).
369    CpNumber,
370    /// `0x0013` CP_duration (uimsbf/n×100ms, 2 bytes).
371    CpDuration,
372    /// `0x0014` CP_CW_combination (CP uimsbf 2B + CW variable; compound, opaque CW).
373    CpCwCombination,
374    /// `0x0015` ECM_datagram (user defined, variable; opaque).
375    EcmDatagram,
376    /// `0x0016` AC_delay_start (tcimsbf/ms, 2 bytes).
377    AcDelayStart,
378    /// `0x0017` AC_delay_stop (tcimsbf/ms, 2 bytes).
379    AcDelayStop,
380    /// `0x0018` CW_encryption (user defined, variable; opaque).
381    CwEncryption,
382    /// `0x0019` ECM_id (uimsbf, 2 bytes).
383    EcmId,
384    /// `0x7000` error_status (2 bytes; see [`EcmgErrorStatus`]).
385    ErrorStatus,
386    /// `0x7001` error_information (user defined, variable).
387    ErrorInformation,
388    /// Any value not in the ECMG⇔SCS registry (DVB-reserved / user-defined).
389    Reserved(u16),
390}
391
392impl EcmgScsParameterType {
393    /// Decode a 16-bit `parameter_type` for the ECMG⇔SCS interface.
394    #[must_use]
395    pub const fn from_u16(v: u16) -> Self {
396        match v {
397            0x0001 => Self::SuperCasId,
398            0x0002 => Self::SectionTspktFlag,
399            0x0003 => Self::DelayStart,
400            0x0004 => Self::DelayStop,
401            0x0005 => Self::TransitionDelayStart,
402            0x0006 => Self::TransitionDelayStop,
403            0x0007 => Self::EcmRepPeriod,
404            0x0008 => Self::MaxStreams,
405            0x0009 => Self::MinCpDuration,
406            0x000A => Self::LeadCw,
407            0x000B => Self::CwPerMsg,
408            0x000C => Self::MaxCompTime,
409            0x000D => Self::AccessCriteria,
410            0x000E => Self::EcmChannelId,
411            0x000F => Self::EcmStreamId,
412            0x0010 => Self::NominalCpDuration,
413            0x0011 => Self::AccessCriteriaTransferMode,
414            0x0012 => Self::CpNumber,
415            0x0013 => Self::CpDuration,
416            0x0014 => Self::CpCwCombination,
417            0x0015 => Self::EcmDatagram,
418            0x0016 => Self::AcDelayStart,
419            0x0017 => Self::AcDelayStop,
420            0x0018 => Self::CwEncryption,
421            0x0019 => Self::EcmId,
422            0x7000 => Self::ErrorStatus,
423            0x7001 => Self::ErrorInformation,
424            other => Self::Reserved(other),
425        }
426    }
427
428    /// The 16-bit wire value.
429    #[must_use]
430    pub const fn to_u16(self) -> u16 {
431        match self {
432            Self::SuperCasId => 0x0001,
433            Self::SectionTspktFlag => 0x0002,
434            Self::DelayStart => 0x0003,
435            Self::DelayStop => 0x0004,
436            Self::TransitionDelayStart => 0x0005,
437            Self::TransitionDelayStop => 0x0006,
438            Self::EcmRepPeriod => 0x0007,
439            Self::MaxStreams => 0x0008,
440            Self::MinCpDuration => 0x0009,
441            Self::LeadCw => 0x000A,
442            Self::CwPerMsg => 0x000B,
443            Self::MaxCompTime => 0x000C,
444            Self::AccessCriteria => 0x000D,
445            Self::EcmChannelId => 0x000E,
446            Self::EcmStreamId => 0x000F,
447            Self::NominalCpDuration => 0x0010,
448            Self::AccessCriteriaTransferMode => 0x0011,
449            Self::CpNumber => 0x0012,
450            Self::CpDuration => 0x0013,
451            Self::CpCwCombination => 0x0014,
452            Self::EcmDatagram => 0x0015,
453            Self::AcDelayStart => 0x0016,
454            Self::AcDelayStop => 0x0017,
455            Self::CwEncryption => 0x0018,
456            Self::EcmId => 0x0019,
457            Self::ErrorStatus => 0x7000,
458            Self::ErrorInformation => 0x7001,
459            Self::Reserved(v) => v,
460        }
461    }
462
463    /// Label per the project's `name()` convention (the spec token).
464    #[must_use]
465    pub fn name(&self) -> &'static str {
466        match self {
467            Self::SuperCasId => "Super_CAS_id",
468            Self::SectionTspktFlag => "section_TSpkt_flag",
469            Self::DelayStart => "delay_start",
470            Self::DelayStop => "delay_stop",
471            Self::TransitionDelayStart => "transition_delay_start",
472            Self::TransitionDelayStop => "transition_delay_stop",
473            Self::EcmRepPeriod => "ECM_rep_period",
474            Self::MaxStreams => "max_streams",
475            Self::MinCpDuration => "min_CP_duration",
476            Self::LeadCw => "lead_CW",
477            Self::CwPerMsg => "CW_per_msg",
478            Self::MaxCompTime => "max_comp_time",
479            Self::AccessCriteria => "access_criteria",
480            Self::EcmChannelId => "ECM_channel_id",
481            Self::EcmStreamId => "ECM_stream_id",
482            Self::NominalCpDuration => "nominal_CP_duration",
483            Self::AccessCriteriaTransferMode => "access_criteria_transfer_mode",
484            Self::CpNumber => "CP_number",
485            Self::CpDuration => "CP_duration",
486            Self::CpCwCombination => "CP_CW_combination",
487            Self::EcmDatagram => "ECM_datagram",
488            Self::AcDelayStart => "AC_delay_start",
489            Self::AcDelayStop => "AC_delay_stop",
490            Self::CwEncryption => "CW_encryption",
491            Self::EcmId => "ECM_id",
492            Self::ErrorStatus => "error_status",
493            Self::ErrorInformation => "error_information",
494            Self::Reserved(_) => "reserved",
495        }
496    }
497}
498dvb_common::impl_spec_display!(EcmgScsParameterType, Reserved);
499
500// ===========================================================================
501// parameter_type — EMMG/PDG ⇔ MUX (Table 7, §6.2.2 p. 42)
502// ===========================================================================
503
504/// EMMG/PDG⇔MUX `parameter_type` values (TS 103 197 Table 7, §6.2.2 p. 42).
505#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
506#[cfg_attr(feature = "serde", derive(serde::Serialize))]
507#[non_exhaustive]
508pub enum EmmgMuxParameterType {
509    /// `0x0001` client_id (uimsbf, 4 bytes).
510    ClientId,
511    /// `0x0002` section_TSpkt_flag (uimsbf, 1 byte).
512    SectionTspktFlag,
513    /// `0x0003` data_channel_id (uimsbf, 2 bytes).
514    DataChannelId,
515    /// `0x0004` data_stream_id (uimsbf, 2 bytes).
516    DataStreamId,
517    /// `0x0005` datagram (user defined, variable; opaque).
518    Datagram,
519    /// `0x0006` bandwidth (uimsbf/kbit/s, 2 bytes).
520    Bandwidth,
521    /// `0x0007` data_type (uimsbf, 1 byte; see [`DataType`]).
522    DataType,
523    /// `0x0008` data_id (uimsbf, 2 bytes).
524    DataId,
525    /// `0x7000` error_status (2 bytes; see [`EmmgErrorStatus`]).
526    ErrorStatus,
527    /// `0x7001` error_information (user defined, variable).
528    ErrorInformation,
529    /// Any value not in the EMMG/PDG⇔MUX registry (DVB-reserved / user-defined).
530    Reserved(u16),
531}
532
533impl EmmgMuxParameterType {
534    /// Decode a 16-bit `parameter_type` for the EMMG/PDG⇔MUX interface.
535    #[must_use]
536    pub const fn from_u16(v: u16) -> Self {
537        match v {
538            0x0001 => Self::ClientId,
539            0x0002 => Self::SectionTspktFlag,
540            0x0003 => Self::DataChannelId,
541            0x0004 => Self::DataStreamId,
542            0x0005 => Self::Datagram,
543            0x0006 => Self::Bandwidth,
544            0x0007 => Self::DataType,
545            0x0008 => Self::DataId,
546            0x7000 => Self::ErrorStatus,
547            0x7001 => Self::ErrorInformation,
548            other => Self::Reserved(other),
549        }
550    }
551
552    /// The 16-bit wire value.
553    #[must_use]
554    pub const fn to_u16(self) -> u16 {
555        match self {
556            Self::ClientId => 0x0001,
557            Self::SectionTspktFlag => 0x0002,
558            Self::DataChannelId => 0x0003,
559            Self::DataStreamId => 0x0004,
560            Self::Datagram => 0x0005,
561            Self::Bandwidth => 0x0006,
562            Self::DataType => 0x0007,
563            Self::DataId => 0x0008,
564            Self::ErrorStatus => 0x7000,
565            Self::ErrorInformation => 0x7001,
566            Self::Reserved(v) => v,
567        }
568    }
569
570    /// Label per the project's `name()` convention (the spec token).
571    #[must_use]
572    pub fn name(&self) -> &'static str {
573        match self {
574            Self::ClientId => "client_id",
575            Self::SectionTspktFlag => "section_TSpkt_flag",
576            Self::DataChannelId => "data_channel_id",
577            Self::DataStreamId => "data_stream_id",
578            Self::Datagram => "datagram",
579            Self::Bandwidth => "bandwidth",
580            Self::DataType => "data_type",
581            Self::DataId => "data_id",
582            Self::ErrorStatus => "error_status",
583            Self::ErrorInformation => "error_information",
584            Self::Reserved(_) => "reserved",
585        }
586    }
587}
588dvb_common::impl_spec_display!(EmmgMuxParameterType, Reserved);
589
590/// Interface-tagged `parameter_type`: decode a raw value once the [`Interface`]
591/// is known.
592#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
593#[cfg_attr(feature = "serde", derive(serde::Serialize))]
594#[non_exhaustive]
595pub enum ParameterType {
596    /// An ECMG⇔SCS parameter_type.
597    EcmgScs(EcmgScsParameterType),
598    /// An EMMG/PDG⇔MUX parameter_type.
599    EmmgPdgMux(EmmgMuxParameterType),
600}
601
602impl ParameterType {
603    /// Decode a raw 16-bit `parameter_type` for the given interface.
604    #[must_use]
605    pub const fn from_u16(iface: Interface, v: u16) -> Self {
606        match iface {
607            Interface::EcmgScs => Self::EcmgScs(EcmgScsParameterType::from_u16(v)),
608            Interface::EmmgPdgMux => Self::EmmgPdgMux(EmmgMuxParameterType::from_u16(v)),
609        }
610    }
611
612    /// The 16-bit wire value.
613    #[must_use]
614    pub const fn to_u16(self) -> u16 {
615        match self {
616            Self::EcmgScs(p) => p.to_u16(),
617            Self::EmmgPdgMux(p) => p.to_u16(),
618        }
619    }
620
621    /// The interface this parameter_type was decoded against.
622    #[must_use]
623    pub const fn interface(self) -> Interface {
624        match self {
625            Self::EcmgScs(_) => Interface::EcmgScs,
626            Self::EmmgPdgMux(_) => Interface::EmmgPdgMux,
627        }
628    }
629
630    /// Label per the project's `name()` convention.
631    #[must_use]
632    pub fn name(&self) -> &'static str {
633        match self {
634            Self::EcmgScs(p) => p.name(),
635            Self::EmmgPdgMux(p) => p.name(),
636        }
637    }
638}
639dvb_common::impl_spec_display!(ParameterType);
640
641// ===========================================================================
642// EMMG/PDG value sub-tables (§6.2.3)
643// ===========================================================================
644
645/// `data_type` values (TS 103 197 §6.2.3 p. 42) — what a `datagram` carries.
646#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
647#[cfg_attr(feature = "serde", derive(serde::Serialize))]
648#[non_exhaustive]
649pub enum DataType {
650    /// `0x00` EMM.
651    Emm,
652    /// `0x01` private data.
653    PrivateData,
654    /// `0x02` DVB reserved (ECM).
655    Ecm,
656    /// Any other value (DVB reserved).
657    Reserved(u8),
658}
659
660impl DataType {
661    /// Decode a `data_type` byte.
662    #[must_use]
663    pub const fn from_u8(v: u8) -> Self {
664        match v {
665            0x00 => Self::Emm,
666            0x01 => Self::PrivateData,
667            0x02 => Self::Ecm,
668            other => Self::Reserved(other),
669        }
670    }
671
672    /// The wire byte.
673    #[must_use]
674    pub const fn to_u8(self) -> u8 {
675        match self {
676            Self::Emm => 0x00,
677            Self::PrivateData => 0x01,
678            Self::Ecm => 0x02,
679            Self::Reserved(v) => v,
680        }
681    }
682
683    /// Label per the project's `name()` convention.
684    #[must_use]
685    pub fn name(&self) -> &'static str {
686        match self {
687            Self::Emm => "EMM",
688            Self::PrivateData => "private data",
689            Self::Ecm => "ECM",
690            Self::Reserved(_) => "reserved",
691        }
692    }
693}
694dvb_common::impl_spec_display!(DataType, Reserved);
695
696/// `section_TSpkt_flag` values (TS 103 197 §6.2.3 p. 43) — the datagram framing
697/// in `datagram` parameters. (The same flag, with the same meaning, is carried
698/// on the ECMG⇔SCS interface for `ECM_datagram`.)
699#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
700#[cfg_attr(feature = "serde", derive(serde::Serialize))]
701#[non_exhaustive]
702pub enum SectionTspktFlag {
703    /// `0x00` EMMs / private datagrams in MPEG-2 section format.
704    SectionFormat,
705    /// `0x01` MPEG-2 TS packet format (all TS packets 188 bytes).
706    TsPacketFormat,
707    /// `0x02` arbitrary-length EMMs/KMMs per IP Datacast SPP (annex N).
708    ArbitraryLength,
709    /// Any other value (DVB reserved).
710    Reserved(u8),
711}
712
713impl SectionTspktFlag {
714    /// Decode a `section_TSpkt_flag` byte.
715    #[must_use]
716    pub const fn from_u8(v: u8) -> Self {
717        match v {
718            0x00 => Self::SectionFormat,
719            0x01 => Self::TsPacketFormat,
720            0x02 => Self::ArbitraryLength,
721            other => Self::Reserved(other),
722        }
723    }
724
725    /// The wire byte.
726    #[must_use]
727    pub const fn to_u8(self) -> u8 {
728        match self {
729            Self::SectionFormat => 0x00,
730            Self::TsPacketFormat => 0x01,
731            Self::ArbitraryLength => 0x02,
732            Self::Reserved(v) => v,
733        }
734    }
735
736    /// Label per the project's `name()` convention.
737    #[must_use]
738    pub fn name(&self) -> &'static str {
739        match self {
740            Self::SectionFormat => "section_format",
741            Self::TsPacketFormat => "ts_packet_format",
742            Self::ArbitraryLength => "arbitrary_length",
743            Self::Reserved(_) => "reserved",
744        }
745    }
746}
747dvb_common::impl_spec_display!(SectionTspktFlag, Reserved);
748
749// ===========================================================================
750// error_status (Table 6 / Table 8)
751// ===========================================================================
752
753/// ECMG⇔SCS `error_status` values (TS 103 197 Table 6, §5.6 p. 39).
754#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
755#[cfg_attr(feature = "serde", derive(serde::Serialize))]
756#[non_exhaustive]
757pub enum EcmgErrorStatus {
758    /// `0x0001` invalid message.
759    InvalidMessage,
760    /// `0x0002` unsupported protocol version.
761    UnsupportedProtocolVersion,
762    /// `0x0003` unknown message_type value.
763    UnknownMessageType,
764    /// `0x0004` message too long.
765    MessageTooLong,
766    /// `0x0005` unknown Super_CAS_id value.
767    UnknownSuperCasId,
768    /// `0x0006` unknown ECM_channel_id value.
769    UnknownEcmChannelId,
770    /// `0x0007` unknown ECM_stream_id value.
771    UnknownEcmStreamId,
772    /// `0x0008` too many channels on this ECMG.
773    TooManyChannels,
774    /// `0x0009` too many ECM streams on this channel.
775    TooManyStreamsOnChannel,
776    /// `0x000A` too many ECM streams on this ECMG.
777    TooManyStreamsOnEcmg,
778    /// `0x000B` not enough control words to compute ECM.
779    NotEnoughControlWords,
780    /// `0x000C` ECMG out of storage capacity.
781    OutOfStorage,
782    /// `0x000D` ECMG out of computational resources.
783    OutOfResources,
784    /// `0x000E` unknown parameter_type value.
785    UnknownParameterType,
786    /// `0x000F` inconsistent length for DVB parameter.
787    InconsistentLength,
788    /// `0x0010` missing mandatory DVB parameter.
789    MissingMandatoryParameter,
790    /// `0x0011` invalid value for DVB parameter.
791    InvalidParameterValue,
792    /// `0x0012` unknown ECM_id value.
793    UnknownEcmId,
794    /// `0x0013` ECM_channel_id value already in use.
795    EcmChannelIdInUse,
796    /// `0x0014` ECM_stream_id value already in use.
797    EcmStreamIdInUse,
798    /// `0x0015` ECM_id value already in use.
799    EcmIdInUse,
800    /// `0x7000` unknown error.
801    UnknownError,
802    /// `0x7001` unrecoverable error.
803    UnrecoverableError,
804    /// Any value not in the registry (DVB-reserved / CA-system / user-defined).
805    Reserved(u16),
806}
807
808impl EcmgErrorStatus {
809    /// Decode a 16-bit `error_status` value.
810    #[must_use]
811    pub const fn from_u16(v: u16) -> Self {
812        match v {
813            0x0001 => Self::InvalidMessage,
814            0x0002 => Self::UnsupportedProtocolVersion,
815            0x0003 => Self::UnknownMessageType,
816            0x0004 => Self::MessageTooLong,
817            0x0005 => Self::UnknownSuperCasId,
818            0x0006 => Self::UnknownEcmChannelId,
819            0x0007 => Self::UnknownEcmStreamId,
820            0x0008 => Self::TooManyChannels,
821            0x0009 => Self::TooManyStreamsOnChannel,
822            0x000A => Self::TooManyStreamsOnEcmg,
823            0x000B => Self::NotEnoughControlWords,
824            0x000C => Self::OutOfStorage,
825            0x000D => Self::OutOfResources,
826            0x000E => Self::UnknownParameterType,
827            0x000F => Self::InconsistentLength,
828            0x0010 => Self::MissingMandatoryParameter,
829            0x0011 => Self::InvalidParameterValue,
830            0x0012 => Self::UnknownEcmId,
831            0x0013 => Self::EcmChannelIdInUse,
832            0x0014 => Self::EcmStreamIdInUse,
833            0x0015 => Self::EcmIdInUse,
834            0x7000 => Self::UnknownError,
835            0x7001 => Self::UnrecoverableError,
836            other => Self::Reserved(other),
837        }
838    }
839
840    /// The 16-bit wire value.
841    #[must_use]
842    pub const fn to_u16(self) -> u16 {
843        match self {
844            Self::InvalidMessage => 0x0001,
845            Self::UnsupportedProtocolVersion => 0x0002,
846            Self::UnknownMessageType => 0x0003,
847            Self::MessageTooLong => 0x0004,
848            Self::UnknownSuperCasId => 0x0005,
849            Self::UnknownEcmChannelId => 0x0006,
850            Self::UnknownEcmStreamId => 0x0007,
851            Self::TooManyChannels => 0x0008,
852            Self::TooManyStreamsOnChannel => 0x0009,
853            Self::TooManyStreamsOnEcmg => 0x000A,
854            Self::NotEnoughControlWords => 0x000B,
855            Self::OutOfStorage => 0x000C,
856            Self::OutOfResources => 0x000D,
857            Self::UnknownParameterType => 0x000E,
858            Self::InconsistentLength => 0x000F,
859            Self::MissingMandatoryParameter => 0x0010,
860            Self::InvalidParameterValue => 0x0011,
861            Self::UnknownEcmId => 0x0012,
862            Self::EcmChannelIdInUse => 0x0013,
863            Self::EcmStreamIdInUse => 0x0014,
864            Self::EcmIdInUse => 0x0015,
865            Self::UnknownError => 0x7000,
866            Self::UnrecoverableError => 0x7001,
867            Self::Reserved(v) => v,
868        }
869    }
870
871    /// Label per the project's `name()` convention.
872    #[must_use]
873    pub fn name(&self) -> &'static str {
874        match self {
875            Self::InvalidMessage => "invalid message",
876            Self::UnsupportedProtocolVersion => "unsupported protocol version",
877            Self::UnknownMessageType => "unknown message_type value",
878            Self::MessageTooLong => "message too long",
879            Self::UnknownSuperCasId => "unknown Super_CAS_id value",
880            Self::UnknownEcmChannelId => "unknown ECM_channel_id value",
881            Self::UnknownEcmStreamId => "unknown ECM_stream_id value",
882            Self::TooManyChannels => "too many channels on this ECMG",
883            Self::TooManyStreamsOnChannel => "too many ECM streams on this channel",
884            Self::TooManyStreamsOnEcmg => "too many ECM streams on this ECMG",
885            Self::NotEnoughControlWords => "not enough control words to compute ECM",
886            Self::OutOfStorage => "ECMG out of storage capacity",
887            Self::OutOfResources => "ECMG out of computational resources",
888            Self::UnknownParameterType => "unknown parameter_type value",
889            Self::InconsistentLength => "inconsistent length for DVB parameter",
890            Self::MissingMandatoryParameter => "missing mandatory DVB parameter",
891            Self::InvalidParameterValue => "invalid value for DVB parameter",
892            Self::UnknownEcmId => "unknown ECM_id value",
893            Self::EcmChannelIdInUse => "ECM_channel_id value already in use",
894            Self::EcmStreamIdInUse => "ECM_stream_id value already in use",
895            Self::EcmIdInUse => "ECM_id value already in use",
896            Self::UnknownError => "unknown error",
897            Self::UnrecoverableError => "unrecoverable error",
898            Self::Reserved(_) => "reserved",
899        }
900    }
901}
902dvb_common::impl_spec_display!(EcmgErrorStatus, Reserved);
903
904/// EMMG/PDG⇔MUX `error_status` values (TS 103 197 Table 8, §6.2.6 p. 47).
905#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
906#[cfg_attr(feature = "serde", derive(serde::Serialize))]
907#[non_exhaustive]
908pub enum EmmgErrorStatus {
909    /// `0x0001` invalid message.
910    InvalidMessage,
911    /// `0x0002` unsupported protocol version.
912    UnsupportedProtocolVersion,
913    /// `0x0003` unknown message_type value.
914    UnknownMessageType,
915    /// `0x0004` message too long.
916    MessageTooLong,
917    /// `0x0005` unknown data_stream_id value.
918    UnknownDataStreamId,
919    /// `0x0006` unknown data_channel_id value.
920    UnknownDataChannelId,
921    /// `0x0007` too many channels on this MUX.
922    TooManyChannels,
923    /// `0x0008` too many data streams on this channel.
924    TooManyStreamsOnChannel,
925    /// `0x0009` too many data streams on this MUX.
926    TooManyStreamsOnMux,
927    /// `0x000A` unknown parameter_type.
928    UnknownParameterType,
929    /// `0x000B` inconsistent length for DVB parameter.
930    InconsistentLength,
931    /// `0x000C` missing mandatory DVB parameter.
932    MissingMandatoryParameter,
933    /// `0x000D` invalid value for DVB parameter.
934    InvalidParameterValue,
935    /// `0x000E` unknown client_id value.
936    UnknownClientId,
937    /// `0x000F` exceeded bandwidth.
938    ExceededBandwidth,
939    /// `0x0010` unknown data_id value.
940    UnknownDataId,
941    /// `0x0011` data_channel_id value already in use.
942    DataChannelIdInUse,
943    /// `0x0012` data_stream_id value already in use.
944    DataStreamIdInUse,
945    /// `0x0013` data_id value already in use.
946    DataIdInUse,
947    /// `0x0014` client_id value already in use.
948    ClientIdInUse,
949    /// `0x7000` unknown error.
950    UnknownError,
951    /// `0x7001` unrecoverable error.
952    UnrecoverableError,
953    /// Any value not in the registry (DVB-reserved / CA-system / user-defined).
954    Reserved(u16),
955}
956
957impl EmmgErrorStatus {
958    /// Decode a 16-bit `error_status` value.
959    #[must_use]
960    pub const fn from_u16(v: u16) -> Self {
961        match v {
962            0x0001 => Self::InvalidMessage,
963            0x0002 => Self::UnsupportedProtocolVersion,
964            0x0003 => Self::UnknownMessageType,
965            0x0004 => Self::MessageTooLong,
966            0x0005 => Self::UnknownDataStreamId,
967            0x0006 => Self::UnknownDataChannelId,
968            0x0007 => Self::TooManyChannels,
969            0x0008 => Self::TooManyStreamsOnChannel,
970            0x0009 => Self::TooManyStreamsOnMux,
971            0x000A => Self::UnknownParameterType,
972            0x000B => Self::InconsistentLength,
973            0x000C => Self::MissingMandatoryParameter,
974            0x000D => Self::InvalidParameterValue,
975            0x000E => Self::UnknownClientId,
976            0x000F => Self::ExceededBandwidth,
977            0x0010 => Self::UnknownDataId,
978            0x0011 => Self::DataChannelIdInUse,
979            0x0012 => Self::DataStreamIdInUse,
980            0x0013 => Self::DataIdInUse,
981            0x0014 => Self::ClientIdInUse,
982            0x7000 => Self::UnknownError,
983            0x7001 => Self::UnrecoverableError,
984            other => Self::Reserved(other),
985        }
986    }
987
988    /// The 16-bit wire value.
989    #[must_use]
990    pub const fn to_u16(self) -> u16 {
991        match self {
992            Self::InvalidMessage => 0x0001,
993            Self::UnsupportedProtocolVersion => 0x0002,
994            Self::UnknownMessageType => 0x0003,
995            Self::MessageTooLong => 0x0004,
996            Self::UnknownDataStreamId => 0x0005,
997            Self::UnknownDataChannelId => 0x0006,
998            Self::TooManyChannels => 0x0007,
999            Self::TooManyStreamsOnChannel => 0x0008,
1000            Self::TooManyStreamsOnMux => 0x0009,
1001            Self::UnknownParameterType => 0x000A,
1002            Self::InconsistentLength => 0x000B,
1003            Self::MissingMandatoryParameter => 0x000C,
1004            Self::InvalidParameterValue => 0x000D,
1005            Self::UnknownClientId => 0x000E,
1006            Self::ExceededBandwidth => 0x000F,
1007            Self::UnknownDataId => 0x0010,
1008            Self::DataChannelIdInUse => 0x0011,
1009            Self::DataStreamIdInUse => 0x0012,
1010            Self::DataIdInUse => 0x0013,
1011            Self::ClientIdInUse => 0x0014,
1012            Self::UnknownError => 0x7000,
1013            Self::UnrecoverableError => 0x7001,
1014            Self::Reserved(v) => v,
1015        }
1016    }
1017
1018    /// Label per the project's `name()` convention.
1019    #[must_use]
1020    pub fn name(&self) -> &'static str {
1021        match self {
1022            Self::InvalidMessage => "invalid message",
1023            Self::UnsupportedProtocolVersion => "unsupported protocol version",
1024            Self::UnknownMessageType => "unknown message_type value",
1025            Self::MessageTooLong => "message too long",
1026            Self::UnknownDataStreamId => "unknown data_stream_id value",
1027            Self::UnknownDataChannelId => "unknown data_channel_id value",
1028            Self::TooManyChannels => "too many channels on this MUX",
1029            Self::TooManyStreamsOnChannel => "too many data streams on this channel",
1030            Self::TooManyStreamsOnMux => "too many data streams on this MUX",
1031            Self::UnknownParameterType => "unknown parameter_type",
1032            Self::InconsistentLength => "inconsistent length for DVB parameter",
1033            Self::MissingMandatoryParameter => "missing mandatory DVB parameter",
1034            Self::InvalidParameterValue => "invalid value for DVB parameter",
1035            Self::UnknownClientId => "unknown client_id value",
1036            Self::ExceededBandwidth => "exceeded bandwidth",
1037            Self::UnknownDataId => "unknown data_id value",
1038            Self::DataChannelIdInUse => "data_channel_id value already in use",
1039            Self::DataStreamIdInUse => "data_stream_id value already in use",
1040            Self::DataIdInUse => "data_id value already in use",
1041            Self::ClientIdInUse => "client_id value already in use",
1042            Self::UnknownError => "unknown error",
1043            Self::UnrecoverableError => "unrecoverable error",
1044            Self::Reserved(_) => "reserved",
1045        }
1046    }
1047}
1048dvb_common::impl_spec_display!(EmmgErrorStatus, Reserved);