Skip to main content

rds_rs/
types.rs

1#![allow(dead_code)]
2// Need to allow unused parens because of the way that the
3// modular-bitfields-msb Debug attribute macro expands.
4#![allow(unused_parens)]
5
6use heapless::HistoryBuf;
7use libm::floorf;
8use modular_bitfield_msb::prelude::*;
9
10/// An RDS group, when transmitted, is a 104 bit item consisting of 4 blocks
11/// (A, B, C, D). Each block consists of 26 bits: a 16 data information word
12/// followed by a 10 bit checkword. The receiver strips the 10 bit checkword,
13/// and evaluates it to determine if the the block should be passed along for
14/// decoding.
15///
16/// See the RDS Standard section 2.1.
17pub struct Group {
18    pub a: Option<u16>, // Block A data word.
19    pub b: Option<u16>, // Block B data word.
20    pub c: Option<u16>, // Block C data word.
21    pub d: Option<u16>, // Block D data word.
22}
23
24/// Maximum number of transparent data channels we track.
25/// See the RBDS Standard section 4.18.
26pub const NUM_TDC: usize = 32;
27
28/// Number of transparent data bytes kept per channel
29pub const TDC_LEN: usize = 32;
30
31/// Group type version.
32/// See the RDS Standard section 3.1.3.
33/// #[derive(BitfieldSpecifier)]
34#[derive(BitfieldSpecifier, Debug, PartialEq, Eq)]
35#[bits = 1]
36pub enum GroupVersion {
37    A = 0,
38    B = 1,
39}
40
41/// Group type code and version.
42/// See the RDS Standard section 3.1.3 - Table 3.
43#[bitfield(bits = 5)]
44#[derive(BitfieldSpecifier, Default, Copy, Clone, PartialEq, Eq)]
45pub struct GroupType {
46    #[skip(setters)]
47    pub code: B4, // Group type code.
48    #[skip(setters)]
49    pub version: GroupVersion, // Group version (A/B).
50}
51
52/// Decoder identification and Dynamic PTY indicator / DI codes
53/// See the RDS Standard section 3.2.1.5.
54#[bitfield(bits = 4)]
55#[derive(Default, Debug, Clone, PartialEq, Eq)]
56pub struct DiCodes {
57    pub dynamic_pty: bool,     // d3
58    pub compressed: bool,      // d2
59    pub artificial_head: bool, // d1
60    pub stereo: bool,          // d0
61}
62
63/// Program Item Number Code (PIN)
64/// The scheduled broadcast start time and day of month as published by
65/// the broadcaster.
66/// See the RBDS Standard section 3.2.1.7.
67#[bitfield(bits = 16)]
68#[derive(Default, Clone, Copy, PartialEq, Eq)]
69pub struct Pin {
70    #[skip(setters)]
71    pub day: B5,
72    #[skip(setters)]
73    pub hour: B5,
74    #[skip(setters)]
75    pub minute: B6,
76}
77
78/// Clock Time and Date (CT)
79#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
80pub struct Clock {
81    pub mjd: u32,                  // Modified Julian Day.
82    pub hour: u8,                  // UTC hour.
83    pub minute: u8,                // UTC minute.
84    pub utc_offset_half_hours: i8, // Local time offset from UTC in half-hours
85}
86
87const AVG_DAYS_PER_MONTH: f32 = 30.6001;
88const AVT_DAYS_PER_YEAR: f32 = 365.25;
89const MJD_JAN_1_2000: f32 = 15078.2; // Likely 2000 January 1, 04:48 UT
90
91impl Clock {
92    fn yp(&self) -> i32 {
93        // Y' = int [ (MJD - 15078,2) / 365,25 ]
94        (((self.mjd as f32) - 15078.2) / AVT_DAYS_PER_YEAR) as i32
95    }
96    fn k(&self) -> i32 {
97        // If M' = 14 or M' = 15, then K = 1; else K = 0
98        match self.mp() {
99            14 | 15 => 1,
100            _ => 0,
101        }
102    }
103    pub fn year(&self) -> i32 {
104        1900 + self.yp() + self.k()
105    }
106    fn mp(&self) -> i32 {
107        // int { [ MJD - 14956,1 - int (Y' × 365,25) ] / 30,6001 }
108        let a: f32 = (self.mjd as f32) - 14956.1;
109        let b: f32 = (self.yp() as f32) * AVT_DAYS_PER_YEAR;
110        ((a - floorf(b)) / AVG_DAYS_PER_MONTH) as i32
111    }
112    pub fn month(&self) -> i32 {
113        // M = M' - 1 - K × 12
114        self.mp() - 1 - self.k() * 12
115    }
116    pub fn day(&self) -> i32 {
117        // D = MJD - 14956 - int ( Y' × 365,25 ) - int ( M' × 30,6001 )
118        let a: i32 = ((self.yp() as f32) * AVT_DAYS_PER_YEAR) as i32;
119        let b: i32 = ((self.mp() as f32) * AVG_DAYS_PER_MONTH) as i32;
120        (self.mjd as i32) - 14956 - a - b
121    }
122}
123
124/// Bitflags indicating the RDS fields that are valid / have been received
125/// and decoded.
126#[bitfield(bits = 21)]
127#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
128pub struct ValidFields {
129    /// Alternative Frequency (AF) data for the tuned network.
130    pub af: bool,
131    /// Alternative Freqnency data for the other network (ON).
132    pub on_freqs: bool,
133    /// Mapped alternative frequency data for the other network.    
134    pub map_freqs: bool,
135    /// Clock data.
136    pub clock: bool,
137    /// Emergency Warning System (EWS).
138    pub ews: bool,
139    /// Program Item Number (PIN) for tuned network (TN).
140    pub pin: bool,
141    /// Program Item Number (PIN) for other network (ON).
142    pub pin_on: bool,
143    /// Program Identification (PI code).
144    pub pi: bool,
145    /// Program service name (PS) for the tuned network (TN).
146    pub ps: bool,
147    /// Program service name (PS) for the other network (ON).
148    pub ps_on: bool,
149    /// Program type (PTY).
150    pub pty: bool,
151    /// Program type name (PTYN).
152    pub ptyn: bool,
153    /// Radiotext (RT).
154    pub rt: bool,
155    /// Service linked data. See RDSM spec. (3.2.1.8.3).
156    pub slc: bool,
157    /// Transparent data channel data.
158    pub tdc: bool,
159    /// Traffic Announcement (TA) for the tuned network (TN).
160    pub ta: bool,
161    /// Traffic Announcement (TA) for the other network (ON).
162    pub ta_on: bool,
163    /// Traffic Program (TP) for the tuned network (TN).
164    pub tp: bool,
165    /// Traffic Program (TP) for the other network (ON).
166    pub tp_on: bool,
167    /// Music/Speech flag. true=music.
168    pub ms: bool,
169    /// Enhanced other network (EON) data.
170    pub eon: bool,
171}
172
173// Program identification codes and Extended country codes.
174// See the RBDS Standard Annex D.
175#[bitfield(bits = 16)]
176#[derive(Default, Debug, Clone, PartialEq, Eq)]
177pub struct ProgramInformation {
178    #[skip(setters)]
179    pub country_code: B4,
180    #[skip(setters)]
181    pub program_type: B4,
182    #[skip(setters)]
183    pub program_reference_number: u8,
184}
185
186/// A combination of Traffic Program (TP) and Traffic Announcement (TA) codes
187/// See the RBDS Standard section 3.2.1.3.
188///
189/// | TP | TA |  Comment                                                   |
190/// |----|----|------------------------------------------------------------|
191/// | 0  | 0  | This program does not carry traffic announcements nor does |
192/// |    |    | it refer, via EON, to a program that does.                 |
193/// | 0  | 1  | This program carries EON information about another program |
194/// |    |    | which gives traffic information.                           |
195/// | 1  | 0  | This program carries traffic announcements but none are    |
196/// |    |    | being broadcast at present and may also carry EON          |
197/// |    |    | information about other traffic announcements.             |
198/// | 1  | 1  | A traffic announcement is being broadcast on this program  |
199/// |    |    | at present.                                                |
200///
201#[bitfield(bits = 2)]
202#[derive(Default, Clone, PartialEq, Eq)]
203pub struct TrafficCodes {
204    pub tp: bool, // Traffic Program code (TP).
205    pub ta: bool, // Traffic Announcement code (TA).
206}
207
208#[derive(BitfieldSpecifier, Debug, Default, Clone, Copy, PartialEq, Eq)]
209#[bits = 5]
210pub enum ProgramType {
211    #[default]
212    None = 0,
213    News = 1,
214    Information = 2,
215    Sports = 3,
216    Talk = 4,
217    Rock = 5,
218    ClassicRock = 6,
219    AdultHits = 7,
220    SoftRock = 8,
221    Top40 = 9,
222    Country = 10,
223    Oldies = 11,
224    Soft = 12,
225    Nostalgia = 13,
226    Jazz = 14,
227    Classical = 15,
228    RhythmAndBlues = 16,
229    SoftRhythmAndBlues = 17,
230    ForeignLanguage = 18,
231    ReligiousMusic = 19,
232    ReligiousTalk = 20,
233    Personality = 21,
234    Public = 22,
235    College = 23,
236    Unnasigned1 = 24,
237    Unnasigned2 = 25,
238    Unnasigned3 = 26,
239    Unnasigned4 = 27,
240    Unnasigned5 = 28,
241    Weather = 29,
242    EmergencyTest = 30,
243    Emergency = 31,
244}
245
246/// Music/speech (M/S) switch code.
247/// See the RBDS Standard section 3.2.1.4.
248#[derive(BitfieldSpecifier, Debug, Default, Clone, Copy, PartialEq, Eq)]
249#[bits = 1]
250pub enum Content {
251    Speech = 0,
252    #[default]
253    Music = 1,
254}
255
256/// Slow labelling code variant
257#[derive(BitfieldSpecifier, Default, Clone, PartialEq, Eq)]
258#[bits = 3]
259pub enum SlcVariant {
260    #[default]
261    Paging = 0,
262    TmcId = 1,
263    PagingId = 2,
264    Language = 3,
265    NotAssigned4 = 4,
266    NotAssigned5 = 5,
267    Broadcaster = 6,
268    Ews = 7,
269}
270
271#[bitfield(bits = 16)]
272#[derive(Default, Clone, PartialEq, Eq)]
273pub struct SlcData {
274    #[skip(setters)]
275    pub linkage_actuator: bool, // See RDSM spec. (3.2.1.8.3).
276    #[skip(setters)]
277    pub variant: SlcVariant,
278    #[skip(setters)]
279    pub data: B12,
280}
281
282#[derive(Debug, Default, Clone, PartialEq)]
283pub struct TdcData {
284    pub data: [HistoryBuf<u8, TDC_LEN>; NUM_TDC],
285    pub current_channel: u8,
286}
287
288#[bitfield(bits = 37)]
289#[derive(Default, Clone, PartialEq, Eq)]
290pub struct EwsData {
291    // The data is the bottom five bits of block B, and all of C and D.
292    //
293    // The spec says:
294    // > Format and application of these EWS message bits may be
295    // > assigned unilaterally by each country.
296    pub block_b_lsb: B5,
297    pub block_c: u16,
298    pub block_d: u16,
299}