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}