pub const DEFAULT_LINK_ID: u32 = 7_669_206;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RadioPort {
Video,
TelemetryRx,
TelemetryTx,
TunnelRx,
TunnelTx,
AudioRx,
AudioTx,
#[deprecated(note = "use RadioPort::TelemetryRx; port 0x10 is telemetry, not always MAVLink")]
MavlinkRx,
#[deprecated(
note = "use RadioPort::TunnelTx for adaptive-link or RadioPort::TelemetryTx for telemetry uplink"
)]
MavlinkTx,
#[deprecated(note = "use RadioPort::TunnelRx")]
DataRx,
Custom(u8),
}
impl RadioPort {
#[allow(deprecated)]
pub const fn as_u8(self) -> u8 {
match self {
Self::Video => 0,
Self::TelemetryRx | Self::MavlinkRx => 0x10,
Self::TelemetryTx => 0x90,
Self::TunnelRx | Self::DataRx => 0x20,
Self::TunnelTx | Self::MavlinkTx => 0xa0,
Self::AudioRx => 0x30,
Self::AudioTx => 0xb0,
Self::Custom(value) => value,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ChannelId(u32);
impl ChannelId {
pub const fn new(raw: u32) -> Self {
Self(raw)
}
pub const fn from_link_port(link_id: u32, port: RadioPort) -> Self {
Self((link_id << 8) | port.as_u8() as u32)
}
pub const fn default_video() -> Self {
Self::from_link_port(DEFAULT_LINK_ID, RadioPort::Video)
}
pub const fn raw(self) -> u32 {
self.0
}
pub const fn to_be_bytes(self) -> [u8; 4] {
self.0.to_be_bytes()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_video_channel_matches_reference_value() {
let id = ChannelId::default_video();
assert_eq!(id.raw(), (DEFAULT_LINK_ID << 8));
assert_eq!(id.to_be_bytes(), id.raw().to_be_bytes());
}
#[test]
fn radio_ports_match_openipc_ground_station_conventions() {
assert_eq!(RadioPort::Video.as_u8(), 0x00);
assert_eq!(RadioPort::TelemetryRx.as_u8(), 0x10);
assert_eq!(RadioPort::TunnelRx.as_u8(), 0x20);
assert_eq!(RadioPort::AudioRx.as_u8(), 0x30);
assert_eq!(RadioPort::TelemetryTx.as_u8(), 0x90);
assert_eq!(RadioPort::TunnelTx.as_u8(), 0xa0);
assert_eq!(RadioPort::AudioTx.as_u8(), 0xb0);
}
}