rustradio/
correlate_access_code.rs

1/*! Correlate Access Code blocks.
2
3For now an initial yes/no bit block. Future work should add tagging.
4*/
5use crate::stream::{ReadStream, Tag, TagValue, WriteStream};
6
7/// `CorrelateAccessCode` outputs 1 if CAC matches.
8#[derive(rustradio_macros::Block)]
9#[rustradio(crate, sync)]
10pub struct CorrelateAccessCode {
11    #[rustradio(in)]
12    src: ReadStream<u8>,
13    #[rustradio(out)]
14    dst: WriteStream<u8>,
15
16    code: Vec<u8>,
17    slide: Vec<u8>,
18    allowed_diffs: usize,
19}
20
21impl CorrelateAccessCode {
22    /// Create new correlate access block.
23    #[must_use]
24    pub fn new(src: ReadStream<u8>, code: Vec<u8>, allowed_diffs: usize) -> (Self, ReadStream<u8>) {
25        let (dst, dr) = crate::stream::new_stream();
26        (
27            Self {
28                src,
29                dst,
30                slide: vec![0; code.len()],
31                code,
32                allowed_diffs,
33            },
34            dr,
35        )
36    }
37    fn process_sync(&mut self, a: u8) -> u8 {
38        self.slide.push(a);
39
40        if self.slide.len() > self.code.len() {
41            self.slide.remove(0);
42        }
43        let diffs = self
44            .slide
45            .iter()
46            .zip(&self.code)
47            .filter(|(a, b)| a != b)
48            .count();
49        u8::from(diffs <= self.allowed_diffs)
50    }
51}
52
53/// `CorrelateAccessCode` outputs 1 if CAC matches.
54#[derive(rustradio_macros::Block)]
55#[rustradio(crate, sync_tag)]
56pub struct CorrelateAccessCodeTag {
57    code: Vec<u8>,
58    #[rustradio(in)]
59    src: ReadStream<u8>,
60    #[rustradio(out)]
61    dst: WriteStream<u8>,
62    slide: Vec<u8>,
63    allowed_diffs: usize,
64    tag: String,
65}
66
67impl CorrelateAccessCodeTag {
68    /// Create new correlate access block.
69    pub fn new<S: Into<String>>(
70        src: ReadStream<u8>,
71        code: Vec<u8>,
72        tag: S,
73        allowed_diffs: usize,
74    ) -> (Self, ReadStream<u8>) {
75        let (dst, dr) = crate::stream::new_stream();
76        (
77            Self {
78                src,
79                tag: tag.into(),
80                dst,
81                slide: vec![0; code.len()],
82                code,
83                allowed_diffs,
84            },
85            dr,
86        )
87    }
88    fn process_sync_tags(&mut self, a: u8, tags: &[Tag]) -> (u8, Vec<Tag>) {
89        self.slide.push(a);
90
91        if self.slide.len() > self.code.len() {
92            self.slide.remove(0);
93        }
94        let diffs = self
95            .slide
96            .iter()
97            .zip(&self.code)
98            .filter(|(a, b)| a != b)
99            .count();
100        let mut tags = tags.to_vec();
101        if diffs <= self.allowed_diffs {
102            tags.push(Tag::new(
103                0,
104                self.tag.clone(),
105                TagValue::U64(
106                    diffs
107                        .try_into()
108                        .expect("can't happen: usize doesn't fit in u64"),
109                ),
110            ));
111        }
112        (a, tags)
113    }
114}