Skip to main content

openipc_core/
channel.rs

1/// OpenIPC's observed default link id from the reference browser receiver.
2///
3/// The Zig project notes this as the SHA1-derived id for
4/// `link_domain = "default"`.
5pub const DEFAULT_LINK_ID: u32 = 7_669_206;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum RadioPort {
9    Video,
10    MavlinkRx,
11    MavlinkTx,
12    DataRx,
13    Custom(u8),
14}
15
16impl RadioPort {
17    pub const fn as_u8(self) -> u8 {
18        match self {
19            Self::Video => 0,
20            Self::MavlinkRx => 0x10,
21            Self::MavlinkTx => 160,
22            Self::DataRx => 32,
23            Self::Custom(value) => value,
24        }
25    }
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29pub struct ChannelId(u32);
30
31impl ChannelId {
32    pub const fn new(raw: u32) -> Self {
33        Self(raw)
34    }
35
36    pub const fn from_link_port(link_id: u32, port: RadioPort) -> Self {
37        Self((link_id << 8) | port.as_u8() as u32)
38    }
39
40    pub const fn default_video() -> Self {
41        Self::from_link_port(DEFAULT_LINK_ID, RadioPort::Video)
42    }
43
44    pub const fn raw(self) -> u32 {
45        self.0
46    }
47
48    pub const fn to_be_bytes(self) -> [u8; 4] {
49        self.0.to_be_bytes()
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn default_video_channel_matches_reference_value() {
59        let id = ChannelId::default_video();
60        assert_eq!(id.raw(), (DEFAULT_LINK_ID << 8));
61        assert_eq!(id.to_be_bytes(), id.raw().to_be_bytes());
62    }
63
64    #[test]
65    fn radio_ports_match_openipc_ground_station_conventions() {
66        assert_eq!(RadioPort::Video.as_u8(), 0x00);
67        assert_eq!(RadioPort::MavlinkRx.as_u8(), 0x10);
68        assert_eq!(RadioPort::DataRx.as_u8(), 0x20);
69        assert_eq!(RadioPort::MavlinkTx.as_u8(), 0xa0);
70    }
71}