1#![allow(dead_code)]
2
3use crate::alt_freq_decoder::get_vhf_frequency;
4use crate::alt_freq_table::{Freq, FreqType};
5use crate::oda::{OdaEntry, decode_oda, is_oda_group_type_used, is_valid_oda_app_id};
6use crate::ptyn::decode_ptyn;
7use crate::radiotext::RtVariant;
8use crate::rds::RdsData;
9use crate::types::{
10 Content, Group, GroupType, GroupVersion, NUM_TDC, Pin, ProgramInformation, ProgramType,
11 SlcData, ValidFields,
12};
13use core::ops::BitOr;
14use modular_bitfield_msb::prelude::*;
15
16#[bitfield(bits = 16)]
18struct GroupType2BlockB {
19 group_type: GroupType, tp: bool, program_type: ProgramType, text_flag: RtVariant,
23 text_segment_addr: B4,
24}
25
26#[bitfield(bits = 16)]
28#[derive(Default, Clone, PartialEq, Eq)]
29struct GroupType3ABlockB {
30 group_type: GroupType, traffic_program: bool, program_type: ProgramType, application_group: GroupType, }
35
36impl BitOr for ValidFields {
37 type Output = Self;
38
39 fn bitor(self, rhs: Self) -> Self {
40 const N: usize = core::mem::size_of::<ValidFields>();
41 let l = self.into_bytes();
42 let r = rhs.into_bytes();
43 let mut m = [0u8; N];
44 for i in 0..N {
45 m[i] = l[i] | r[i];
46 }
47 Self::from_bytes(m)
48 }
49}
50
51impl Group {
52 fn get_type(&self) -> GroupType {
53 GroupType2BlockB::from_bytes(self.b.unwrap().to_be_bytes()).group_type()
54 }
55}
56
57fn decode_block_b_common(block: &GroupType2BlockB, rds_data: &mut RdsData) -> ValidFields {
58 rds_data.tn.traffic.set_tp(block.tp());
59 rds_data.tn.program_type = block.program_type();
60 ValidFields::new().with_tp(true).with_pty(true)
61}
62
63fn decode_group_type_0(
65 group: &Group,
66 rds_data: &mut RdsData,
67 advanced_ps_decoding: bool,
68) -> ValidFields {
69 #[bitfield(bits = 16)]
71 struct BlockB {
72 group_type: GroupType, traffic_program: bool, program_type: ProgramType, traffic_announcement: bool, ms: Content, di_bit: bool, seg_addr: B2, }
80
81 let mut valid = ValidFields::new();
82 let block_b = BlockB::from_bytes(group.b.unwrap().to_be_bytes());
83 if block_b.group_type().version() == GroupVersion::B && group.c.is_some() {
84 let _ = rds_data
85 .alt_freq_decoder
86 .decode_freq_block(group.c, &mut rds_data.alt_freqs);
87 valid.set_af(true);
88 }
89 match block_b.seg_addr() {
92 0 => rds_data.did_pty.set_dynamic_pty(block_b.di_bit()),
93 1 => rds_data.did_pty.set_compressed(block_b.di_bit()),
94 2 => rds_data.did_pty.set_artificial_head(block_b.di_bit()),
95 3 => rds_data.did_pty.set_stereo(block_b.di_bit()),
96 _ => return valid,
97 }
98 if group.d.is_none() {
99 return valid;
100 }
101 rds_data.tn.traffic.set_ta(block_b.traffic_announcement());
102 valid.set_ta(true);
103 rds_data.content = block_b.ms();
104 valid.set_ms(true);
105
106 let pair_idx = 2 * block_b.seg_addr();
107 let ps_bytes = group.d.unwrap().to_be_bytes();
108 if advanced_ps_decoding {
109 if rds_data
110 .tn
111 .ps
112 .update_advanced(pair_idx as usize, ps_bytes[0])
113 {
114 valid.set_ps(true);
115 }
116 if rds_data
117 .tn
118 .ps
119 .update_advanced((pair_idx + 1) as usize, ps_bytes[1])
120 {
121 valid.set_ps(true);
122 }
123 } else {
124 rds_data.tn.ps.update_simple(pair_idx as usize, ps_bytes);
125 valid.set_ps(true);
126 }
127 valid
128}
129
130fn decode_group_type_1(group: &Group, rds_data: &mut RdsData) -> ValidFields {
132 #[bitfield(bits = 16)]
134 struct GroupType1BlockB {
135 group_type: GroupType, traffic_program: bool, program_type: ProgramType, radio_paging_codes: B5, }
140
141 let mut valid = ValidFields::new();
142 let block_b = GroupType1BlockB::from_bytes(group.b.unwrap().to_be_bytes());
143 if block_b.group_type().version() == GroupVersion::A
144 && let Some(group_c) = group.c
145 {
146 rds_data.slc = SlcData::from_bytes(group_c.to_be_bytes());
147 valid.set_slc(true);
148 }
149
150 rds_data.tn.pin = group
155 .d
156 .map(|d| Pin::from_bytes(d.to_be_bytes()))
157 .unwrap_or_default();
158 if group.d.is_some() {
159 valid.set_pin(true);
160 }
161 valid
162}
163
164fn decode_group_type_2a(group: &Group, rds_data: &mut RdsData) -> ValidFields {
167 let block_b = GroupType2BlockB::from_bytes(group.b.unwrap().to_be_bytes());
168 let chars: [Option<[u8; 2]>; 2] =
169 [group.c.map(u16::to_be_bytes), group.d.map(u16::to_be_bytes)];
170 let rt = match block_b.text_flag() {
171 RtVariant::A => &mut rds_data.rt.a,
172 RtVariant::B => &mut rds_data.rt.b,
173 };
174 let addr = (block_b.text_segment_addr() as usize) * 4;
175 rt.update_rt_simple(addr, &chars);
176 if rds_data.rt.decode_rt != block_b.text_flag() {
177 rt.bump_rt_validation_count();
178 }
179 rt.update_rt_advance(addr, &chars);
180 rds_data.rt.decode_rt = block_b.text_flag();
181 ValidFields::new().with_rt(true)
182}
183
184fn decode_group_type_2b(group: &Group, rds_data: &mut RdsData) -> ValidFields {
187 if group.d.is_none() {
188 return ValidFields::new();
189 }
190 let block_b = GroupType2BlockB::from_bytes(group.b.unwrap().to_be_bytes());
191 let chars: [Option<[u8; 2]>; 1] = [group.d.map(u16::to_be_bytes)];
192 let rt = match block_b.text_flag() {
193 RtVariant::A => &mut rds_data.rt.a,
194 RtVariant::B => &mut rds_data.rt.b,
195 };
196 let addr = (block_b.text_segment_addr() as usize) * 2;
197 rt.update_rt_simple(addr, &chars);
198 if rds_data.rt.decode_rt != block_b.text_flag() {
199 rt.bump_rt_validation_count();
200 }
201 rt.update_rt_advance(addr, &chars);
202 rds_data.rt.decode_rt = block_b.text_flag();
203 ValidFields::new().with_rt(true)
204}
205
206fn decode_group_type_3a(group: &Group, rds_data: &mut RdsData) -> ValidFields {
208 let valid = ValidFields::new();
209 if group.d.is_none() {
210 return valid;
211 }
212 let block_b = GroupType3ABlockB::from_bytes(group.b.unwrap().to_be_bytes());
213 let app_id = group.d.unwrap();
214
215 if !is_valid_oda_app_id(app_id) {
221 return valid;
222 }
223
224 let entry = rds_data.oda.get_mut(&app_id);
225 if let Some(e) = entry {
226 e.group_type = block_b.group_type();
227 } else if !rds_data.oda.is_full() {
228 let _ = rds_data.oda.insert(
229 app_id,
230 OdaEntry {
231 group_type: block_b.group_type(),
232 packet_count: 0,
233 },
234 );
235 }
236 valid
237}
238
239fn decode_group_type_3b(group: &Group, rds_data: &mut RdsData) -> ValidFields {
241 decode_oda(group, group.get_type(), rds_data)
243}
244
245fn decode_group_type_4a(group: &Group, rds_data: &mut RdsData) -> ValidFields {
247 #[bitfield(bits = 16)]
249 struct BlockB {
250 group_type: GroupType, traffic_program: bool, program_type: ProgramType, spare: B3, date_msb: B2, }
256 #[bitfield(bits = 16)]
257 struct BlockC {
258 date: B15,
259 hour_msb: B1,
260 }
261 #[bitfield(bits = 16)]
262 struct BlockD {
263 hour: B4,
264 minute: B6,
265 local_offset_dir: B1, local_offset_val: B5, }
268
269 if group.c.is_none() || group.d.is_none() {
270 return ValidFields::new();
271 }
272 let block_b = BlockB::from_bytes(group.b.unwrap().to_be_bytes());
273 let block_c = BlockC::from_bytes(group.b.unwrap().to_be_bytes());
274 let block_d = BlockD::from_bytes(group.b.unwrap().to_be_bytes());
275
276 rds_data.clock.mjd = (u32::from(block_b.date_msb()) << 15) + u32::from(block_c.date());
277 rds_data.clock.hour = (block_c.hour_msb() << 4) + block_d.hour();
278 rds_data.clock.minute = block_d.minute();
279 rds_data.clock.utc_offset_half_hours = if block_d.local_offset_dir() == 0 {
280 block_d.local_offset_val().cast_signed()
281 } else {
282 -(block_d.local_offset_val().cast_signed())
283 };
284 ValidFields::new().with_clock(true)
285}
286
287fn decode_group_type_4b(group: &Group, rds_data: &mut RdsData) -> ValidFields {
289 decode_oda(group, group.get_type(), rds_data)
291}
292
293fn decode_tdc_block(block: u16, rds_data: &mut RdsData) {
294 let channel = rds_data.tdc.current_channel as usize;
297 assert!(channel < NUM_TDC);
299
300 rds_data.tdc.data[channel].write((block >> 8) as u8);
301 rds_data.tdc.data[channel].write((block & 0xff) as u8);
302}
303
304fn decode_group_type_5a(group: &Group, rds_data: &mut RdsData) -> ValidFields {
306 #[bitfield(bits = 16)]
308 struct BlockB {
309 group_type: GroupType, traffic_program: bool, program_type: ProgramType, address: B5,
314 }
315 let block_b = BlockB::from_bytes(group.b.unwrap().to_be_bytes());
316
317 if is_oda_group_type_used(&rds_data.oda, block_b.group_type()) {
318 return decode_oda(group, block_b.group_type(), rds_data);
319 }
320 let mut valid = ValidFields::new();
321 rds_data.tdc.current_channel = block_b.address();
322 if let Some(group_c) = group.c {
323 decode_tdc_block(group_c, rds_data);
324 valid.set_tdc(true);
325 }
326 if let Some(group_d) = group.d {
327 decode_tdc_block(group_d, rds_data);
328 valid.set_tdc(true);
329 }
330 valid
331}
332
333fn decode_group_type_5b(group: &Group, rds_data: &mut RdsData) -> ValidFields {
335 const GROUP_TYPE: GroupType = GroupType::from_bytes([5 << (1 + GroupVersion::B as u8)]);
337 if is_oda_group_type_used(&rds_data.oda, GROUP_TYPE) {
338 return decode_oda(group, GROUP_TYPE, rds_data);
339 }
340 ValidFields::new()
341}
342
343fn decode_group_type_6(group: &Group, rds_data: &mut RdsData) -> ValidFields {
346 #[bitfield(bits = 16)]
347 struct BlockB {
348 group_type: GroupType, traffic_program: bool, program_type: ProgramType, unused: B5,
352 }
353 let block_b = BlockB::from_bytes(group.b.unwrap().to_be_bytes());
354 if is_oda_group_type_used(&rds_data.oda, block_b.group_type()) {
355 return decode_oda(group, block_b.group_type(), rds_data);
356 }
357
358 ValidFields::new()
361}
362
363fn decode_group_type_7a(group: &Group, rds_data: &mut RdsData) -> ValidFields {
365 const GROUP_TYPE: GroupType = GroupType::from_bytes([7 << (1 + GroupVersion::A as u8)]);
367 if is_oda_group_type_used(&rds_data.oda, GROUP_TYPE) {
368 return decode_oda(group, GROUP_TYPE, rds_data);
369 }
370
371 ValidFields::new()
373}
374
375fn decode_group_type_7b(group: &Group, rds_data: &mut RdsData) -> ValidFields {
377 decode_oda(group, group.get_type(), rds_data)
379}
380
381fn decode_group_type_8(group: &Group, rds_data: &mut RdsData) -> ValidFields {
383 let gt = group.get_type();
385 if is_oda_group_type_used(&rds_data.oda, gt) {
386 return decode_oda(group, gt, rds_data);
387 }
388 if gt.version() == GroupVersion::A {
389 }
391 ValidFields::new()
392}
393
394fn decode_group_type_9(group: &Group, rds_data: &mut RdsData) -> ValidFields {
396 let gt = group.get_type();
398 if is_oda_group_type_used(&rds_data.oda, gt) {
399 return decode_oda(group, gt, rds_data);
400 }
401
402 let mut valid = ValidFields::new();
403 if gt.version() == GroupVersion::B {
404 return valid;
405 }
406
407 if group.c.is_none() || group.d.is_none() {
408 return valid;
409 }
410
411 rds_data
412 .ews
413 .set_block_b_lsb((group.b.unwrap() & 0b11111) as u8);
414 rds_data.ews.set_block_c(group.c.unwrap());
415 rds_data.ews.set_block_d(group.d.unwrap());
416 valid.set_ews(true);
417 valid
418}
419
420fn decode_group_type_10a(group: &Group, rds_data: &mut RdsData) -> ValidFields {
422 decode_ptyn(group, rds_data)
424}
425
426fn decode_group_type_10b(group: &Group, rds_data: &mut RdsData) -> ValidFields {
428 match group.get_type().version() {
430 GroupVersion::A => decode_ptyn(group, rds_data),
431 GroupVersion::B => decode_oda(group, group.get_type(), rds_data),
432 }
433}
434
435fn decode_group_type_11(group: &Group, rds_data: &mut RdsData) -> ValidFields {
437 decode_oda(group, group.get_type(), rds_data)
439}
440
441fn decode_group_type_12(group: &Group, rds_data: &mut RdsData) -> ValidFields {
443 decode_oda(group, group.get_type(), rds_data)
445}
446
447fn decode_group_type_13a(group: &Group, _rds_data: &mut RdsData) -> ValidFields {
449 #[bitfield(bits = 16)]
451 struct BlockB {
452 group_type: GroupType, traffic_program: bool, program_type: ProgramType, information: B2,
456 sty: B3,
457 }
458 let _block_b = BlockB::from_bytes(group.b.unwrap().to_be_bytes());
459
460 ValidFields::new()
465}
466
467fn decode_group_type_13b(group: &Group, rds_data: &mut RdsData) -> ValidFields {
469 decode_oda(group, group.get_type(), rds_data)
471}
472
473fn decode_group_type_14a(group: &Group, rds_data: &mut RdsData) -> ValidFields {
475 #[bitfield(bits = 16)]
477 struct BlockB {
478 group_type: GroupType, traffic_program: bool, program_type: ProgramType, tp_on: bool, variant_code: B4,
483 }
484 let block_b = BlockB::from_bytes(group.b.unwrap().to_be_bytes());
485 let mut valid = ValidFields::new().with_tp_on(true);
486 rds_data.on.traffic.set_tp(block_b.tp_on());
487 match block_b.variant_code() {
488 0..=3 => {
489 let idx: usize = 2 * (block_b.variant_code() as usize);
490 if let Some(group_c) = group.c {
491 rds_data.tn.ps.update_simple(idx, group_c.to_be_bytes());
492 valid.set_ps_on(true);
493 }
494 }
495 4 => {
496 let _ = rds_data
497 .on_freq_decoder
498 .decode_freq_block(group.c, &mut rds_data.on_freqs);
499 valid.set_on_freqs(true);
500 }
501 5..=9 => {
502 if let Some(group_c) = group.c {
503 let freqs = group_c.to_be_bytes();
504 if freqs[1] != 0 {
505 rds_data.map_freqs.add(Freq {
506 frequency: get_vhf_frequency(freqs[1]),
507 freq_type: FreqType::SameProgram,
508 });
509 valid.set_map_freqs(true);
510 }
511 }
512 }
513 13 => {
514 if let Some(group_c) = group.c {
515 rds_data.on.traffic.set_ta((group_c & 0b1) != 0);
516 valid.set_ta_on(true);
517 }
518 }
519 14 if group.c.is_some() => {
520 rds_data.on.pin = group
521 .c
522 .map(|c| Pin::from_bytes(c.to_be_bytes()))
523 .unwrap_or_default();
524 valid.set_pin_on(true);
525 }
526 _ => {}
527 }
528 valid
529}
530
531fn decode_group_type_14b(group: &Group, rds_data: &mut RdsData) -> ValidFields {
533 #[bitfield(bits = 16)]
535 struct BlockB {
536 group_type: GroupType, tp: bool, program_type: ProgramType, tp_on: bool, ta_on: bool, unused: B3,
542 }
543 let block_b = BlockB::from_bytes(group.b.unwrap().to_be_bytes());
544 let valid = ValidFields::new()
545 .with_tp(true)
546 .with_ta_on(true)
547 .with_tp_on(true);
548 rds_data.tn.traffic.set_tp(block_b.tp());
549 rds_data.on.traffic.set_ta(block_b.ta_on());
550 rds_data.on.traffic.set_tp(block_b.tp_on());
551 valid
553}
554
555fn decode_group_type_15(_group: &Group, _rds_data: &RdsData) -> ValidFields {
557 ValidFields::new()
558}
559
560pub struct Decoder {
561 advanced_ps_decoding: bool,
562}
563
564impl Decoder {
565 #[must_use]
566 pub fn new(advanced_ps_decoding: bool) -> Self {
567 Decoder {
568 advanced_ps_decoding,
569 }
570 }
571
572 pub fn decode(&mut self, group: &Group, rds_data: &mut RdsData) -> ValidFields {
579 let mut valid = ValidFields::default();
580
581 if let Some(group_a) = group.a {
582 rds_data.program_information = ProgramInformation::from_bytes(group_a.to_be_bytes());
583 valid.set_pi(true);
584 }
585
586 let Some(blk_b) = group.b else {
587 rds_data.valid = rds_data.valid | valid;
588 return valid;
589 };
590
591 let block_b = GroupType2BlockB::from_bytes(blk_b.to_be_bytes());
594 valid = valid | decode_block_b_common(&block_b, rds_data);
595
596 let new_valid = match (block_b.group_type().code(), block_b.group_type().version()) {
597 (0, GroupVersion::A | GroupVersion::B) => {
598 decode_group_type_0(group, rds_data, self.advanced_ps_decoding)
599 }
600 (1, GroupVersion::A | GroupVersion::B) => decode_group_type_1(group, rds_data),
601 (2, GroupVersion::A) => decode_group_type_2a(group, rds_data),
602 (2, GroupVersion::B) => decode_group_type_2b(group, rds_data),
603 (3, GroupVersion::A) => decode_group_type_3a(group, rds_data),
604 (3, GroupVersion::B) => decode_group_type_3b(group, rds_data),
605 (4, GroupVersion::A) => decode_group_type_4a(group, rds_data),
606 (4, GroupVersion::B) => decode_group_type_4b(group, rds_data),
607 (5, GroupVersion::A) => decode_group_type_5a(group, rds_data),
608 (5, GroupVersion::B) => decode_group_type_5b(group, rds_data),
609 (6, GroupVersion::A | GroupVersion::B) => decode_group_type_6(group, rds_data),
610 (7, GroupVersion::A) => decode_group_type_7a(group, rds_data),
611 (7, GroupVersion::B) => decode_group_type_7b(group, rds_data),
612 (8, GroupVersion::A | GroupVersion::B) => decode_group_type_8(group, rds_data),
613 (9, GroupVersion::A | GroupVersion::B) => decode_group_type_9(group, rds_data),
614 (10, GroupVersion::A) => decode_group_type_10a(group, rds_data),
615 (10, GroupVersion::B) => decode_group_type_10b(group, rds_data),
616 (11, GroupVersion::A | GroupVersion::B) => decode_group_type_11(group, rds_data),
617 (12, GroupVersion::A | GroupVersion::B) => decode_group_type_12(group, rds_data),
618 (13, GroupVersion::A) => decode_group_type_13a(group, rds_data),
619 (13, GroupVersion::B) => decode_group_type_13b(group, rds_data),
620 (14, GroupVersion::A) => decode_group_type_14a(group, rds_data),
621 (14, GroupVersion::B) => decode_group_type_14b(group, rds_data),
622 (15, GroupVersion::A | GroupVersion::B) => decode_group_type_15(group, rds_data),
623 _ => {
624 ValidFields::new()
626 }
627 };
628 valid = valid | new_valid; rds_data.valid = rds_data.valid | valid; valid
631 }
632}
633
634#[cfg(test)]
635mod tests;