deep_time/time_parts/to_bin_ccsds.rs
1use crate::{Dt, DtErr, TimeParts};
2
3impl TimeParts {
4 /// Formats this [`TimeParts`] as a **CCSDS C (CUC)** binary time code.
5 ///
6 /// - Fully configurable for round-tripping with [`from_ccsds_c`].
7 /// - Conforms to **CCSDS 301.0-B-4 §3.2 (Level 1)**, including full support
8 /// for the extended P-field (second octet) when `n_coarse > 4` or `n_frac > 3`.
9 ///
10 /// ## Parameters
11 ///
12 /// - `n_coarse`: 1–7 (number of coarse-time octets)
13 /// - `n_frac`: 0–10 (number of fractional octets)
14 /// - `extension`: advisory flag (ignored when larger sizes force the second octet)
15 #[inline]
16 pub fn to_ccsds_c(
17 &self,
18 n_coarse: u8,
19 n_frac: u8,
20 extension: bool,
21 ) -> Result<([u8; Dt::CCSDS_C_AND_D_MAX_SIZE], usize), DtErr> {
22 self.to_dt()?
23 .to_ccsds_c(self.scale, n_coarse, n_frac, extension)
24 }
25
26 /// Formats this [`TimeParts`] as a **CCSDS D (CDS)** binary time code.
27 ///
28 /// - Fully configurable for round-tripping with [`from_ccsds_d`].
29 /// - Conforms to CCSDS 301.0-B-4 §3.3 (Level 1): UTC day count + ms-of-day since
30 /// 1958-01-01 UTC.
31 #[inline]
32 pub fn to_ccsds_d(
33 &self,
34 n_day: u8,
35 sub_ms_code: u8,
36 extension: bool,
37 ) -> Result<([u8; Dt::CCSDS_C_AND_D_MAX_SIZE], usize), DtErr> {
38 self.to_dt()?
39 .to_ccsds_d(self.scale, n_day, sub_ms_code, extension)
40 }
41
42 /// Formats this [`TimeParts`] as a **CCSDS CCS (Calendar Segmented Time Code)**.
43 ///
44 /// Implements **CCSDS 301.0-B-4 §3.4** (Level 1 only).
45 ///
46 /// ## Parameters
47 ///
48 /// - `use_doy`: `false` = Month/Day variant (most common), `true` = Day-of-Year variant
49 /// - `n_subsec`: Number of subsecond BCD octets (`0`–`6`). Each octet holds 2 decimal digits.
50 ///
51 /// ## Returns
52 ///
53 /// `(buffer, written_len)` — the P-field + T-field (big-endian BCD).
54 ///
55 /// ## Precision & Rounding
56 ///
57 /// Fractional seconds are rounded to the nearest representable value at the chosen precision
58 /// (exactly as `to_ccsds_d` does for milliseconds).
59 #[inline]
60 pub fn to_ccsds_ccs(
61 &self,
62 use_doy: bool,
63 n_subsec: u8,
64 ) -> Result<([u8; Dt::CCSDS_CCS_MAX_SIZE], usize), DtErr> {
65 self.to_dt()?.to_ccsds_ccs(self.scale, use_doy, n_subsec)
66 }
67
68 /// Convenience method that automatically selects the most appropriate
69 /// CCSDS binary time code based on this `TimeParts`’s [`Scale`].
70 ///
71 /// ## Automatic selection (matches common mission practice)
72 ///
73 /// - `Scale::TAI` → **CUC** (4 coarse + 4 fractional bytes)
74 /// - Any other `Scale` (UTC, TT, GPS, TCG, …) → converted to UTC and uses **CDS**
75 /// (2 day bytes + 4 ms bytes + 2-byte sub-ms)
76 #[inline]
77 pub fn to_ccsds_bin(&self) -> Result<([u8; Dt::CCSDS_C_AND_D_MAX_SIZE], usize), DtErr> {
78 self.to_dt()?.to_ccsds_bin(self.scale)
79 }
80}