st12_1/lib.rs
1//! SMPTE ST 12-1:2014 "Time and Control Code" — the §9 Linear Time Code
2//! (LTC) 80-bit logical codeword.
3//!
4//! This crate implements exactly the wire structure described in the curated
5//! spec transcription at `st12-1/docs/st12-1.md` (fetched directly from
6//! `https://pub.smpte.org/pub/st12-1/st0012-1-2014.pdf`) — cite that file,
7//! not this doc comment, as the field-semantics oracle.
8//!
9//! - [`LtcFrame`] — the 80-bit LTC codeword (§9.2): BCD hours/minutes/
10//! seconds/frames, the drop-frame and color-frame flags, four
11//! rate-dependent flag bits (resolved via [`FrameRate`]), eight 4-bit
12//! binary groups ("user bits"), and the fixed synchronization word.
13//! - [`FrameRate`] — which of ST 12-1 Table 3's three flag-bit-position
14//! columns (30-frame / 25-frame / 24-frame) applies; the codeword itself
15//! carries no self-describing frame-rate field.
16//! - [`BinaryGroupUsage`] / [`BinaryGroupFlags`] — Table 1's classification
17//! of what the binary groups contain, from the three binary group flag
18//! bits.
19//!
20//! **Scope**: this crate models only the already-demodulated logical 80-bit
21//! codeword — never the §9.3 biphase-mark-encoded physical/analog audio
22//! waveform LTC is carried as on a wire. That line-encoding/clock-recovery
23//! layer is out of scope for this project, the same way it never decodes PCM
24//! or AC-3 audio samples. See `docs/st12-1.md`'s "Scope" section.
25//!
26//! Depends only on `broadcast-common`. `#![no_std]` when the `std` feature
27//! is disabled (this crate needs no heap allocation at all — every field is
28//! a fixed-size scalar).
29//!
30//! # Examples
31//!
32//! Build a frame and round-trip it:
33//!
34//! ```
35//! use broadcast_common::{Parse, Serialize};
36//! use st12_1::LtcFrame;
37//!
38//! let frame = LtcFrame {
39//! hours: 1,
40//! minutes: 23,
41//! seconds: 45,
42//! frames: 13,
43//! drop_frame_flag: false,
44//! color_frame_flag: true,
45//! flag_bit_27: true,
46//! flag_bit_43: true,
47//! flag_bit_58: false,
48//! flag_bit_59: true,
49//! user_bits: [1, 2, 3, 4, 5, 6, 7, 8],
50//! };
51//! let mut bytes = [0u8; st12_1::FRAME_LEN];
52//! frame.serialize_into(&mut bytes).unwrap();
53//! assert_eq!(LtcFrame::parse(&bytes).unwrap(), frame);
54//! ```
55#![cfg_attr(not(feature = "std"), no_std)]
56#![cfg_attr(docsrs, feature(doc_cfg))]
57#![warn(missing_docs)]
58// Runnable examples, embedded so they render on docs.rs and stay in sync with
59// the actual `examples/*.rs` files (shown, not compiled).
60#![doc = "\n## Runnable examples\n"]
61#![doc = "Run with `cargo run -p st12-1 --example <name>`.\n"]
62#![doc = "\n### `build_frame`\n\n```rust,ignore"]
63#![doc = include_str!("../examples/build_frame.rs")]
64#![doc = "```\n\n### `parse_frame`\n\n```rust,ignore"]
65#![doc = include_str!("../examples/parse_frame.rs")]
66#![doc = "```"]
67
68mod error;
69mod frame;
70
71pub use error::{Error, Result};
72pub use frame::{
73 BinaryGroupFlags, BinaryGroupUsage, FRAME_LEN, FrameRate, LtcFrame, MAX_BINARY_GROUP,
74 MAX_FRAMES, MAX_HOURS, MAX_MINUTES_SECONDS, SYNC_WORD,
75};