use std::convert::TryFrom;
use crate::{crtp_utils::crtp_channel_dispatcher, Error, Result};
use crazyflie_link::Packet;
use flume::{Receiver, Sender};
use futures::{lock::Mutex, stream, Sink, SinkExt, Stream, StreamExt};
use crate::crazyflie::PLATFORM_PORT;
use crate::subsystems::supervisor::{CMD_ARM_SYSTEM, CMD_RECOVER_SYSTEM, SUPERVISOR_CH_COMMAND};
const PLATFORM_COMMAND: u8 = 0;
const VERSION_CHANNEL: u8 = 1;
const APP_CHANNEL: u8 = 2;
const PLATFORM_SET_CONT_WAVE: u8 = 0;
const VERSION_GET_PROTOCOL: u8 = 0;
const VERSION_GET_FIRMWARE: u8 = 1;
const VERSION_GET_DEVICE_TYPE: u8 = 2;
pub const APPCHANNEL_MTU: usize = 31;
pub struct Platform {
version_comm: Mutex<(Sender<Packet>, Receiver<Packet>)>,
appchannel_comm: Mutex<Option<(Sender<Packet>, Receiver<Packet>)>>,
uplink: Sender<Packet>,
}
impl Platform {
pub(crate) fn new(uplink: Sender<Packet>, downlink: Receiver<Packet>) -> Self {
let (_, version_downlink, appchannel_downlink, _) = crtp_channel_dispatcher(downlink);
Self {
version_comm: Mutex::new((uplink.clone(), version_downlink)),
appchannel_comm: Mutex::new(Some((uplink.clone(), appchannel_downlink))),
uplink,
}
}
pub async fn protocol_version(&self) -> Result<u8> {
let (uplink, downlink) = &*self.version_comm.lock().await;
let pk = Packet::new(PLATFORM_PORT, VERSION_CHANNEL, vec![VERSION_GET_PROTOCOL]);
uplink.send_async(pk).await?;
let pk = downlink.recv_async().await?;
if pk.get_data()[0] != VERSION_GET_PROTOCOL {
return Err(Error::ProtocolError("Wrong version answer".to_owned()));
}
Ok(pk.get_data()[1])
}
pub async fn firmware_version(&self) -> Result<String> {
let (uplink, downlink) = &*self.version_comm.lock().await;
let pk = Packet::new(PLATFORM_PORT, VERSION_CHANNEL, vec![VERSION_GET_FIRMWARE]);
uplink.send_async(pk).await?;
let pk = downlink.recv_async().await?;
if pk.get_data()[0] != VERSION_GET_FIRMWARE {
return Err(Error::ProtocolError("Wrong version answer".to_owned()));
}
let version = String::from_utf8_lossy(&pk.get_data()[1..]);
Ok(version.to_string())
}
pub async fn device_type_name(&self) -> Result<String> {
let (uplink, downlink) = &*self.version_comm.lock().await;
let pk = Packet::new(
PLATFORM_PORT,
VERSION_CHANNEL,
vec![VERSION_GET_DEVICE_TYPE],
);
uplink.send_async(pk).await?;
let pk = downlink.recv_async().await?;
if pk.get_data()[0] != VERSION_GET_DEVICE_TYPE {
return Err(Error::ProtocolError("Wrong device type answer".to_owned()));
}
let version = String::from_utf8_lossy(&pk.get_data()[1..]);
Ok(version.to_string())
}
pub async fn get_app_channel(
&self,
) -> Option<(
impl Sink<AppChannelPacket> + use<>,
impl Stream<Item = AppChannelPacket> + use<>,
)> {
match self.appchannel_comm.lock().await.take() { Some((tx, rx)) => {
let app_tx = Box::pin(tx.into_sink().with_flat_map(|app_pk: AppChannelPacket| {
stream::once(async { Ok(Packet::new(PLATFORM_PORT, APP_CHANNEL, app_pk.0)) })
}));
let app_rx = rx
.into_stream()
.map(|pk: Packet| AppChannelPacket(pk.get_data().to_vec()))
.boxed();
Some((app_tx, app_rx))
} _ => {
None
}}
}
pub async fn set_cont_wave(&self, activate: bool) -> Result<()> {
let command = if activate { 1 } else { 0 };
self.uplink
.send_async(Packet::new(
PLATFORM_PORT,
PLATFORM_COMMAND,
vec![PLATFORM_SET_CONT_WAVE, command],
))
.await?;
Ok(())
}
#[deprecated(since = "0.8.1", note = "Use [`Supervisor::send_arming_request`](crate::subsystems::supervisor::Supervisor::send_arming_request) instead")]
pub async fn send_arming_request(&self, do_arm: bool) -> Result<()> {
let command = if do_arm { 1u8 } else { 0u8 };
self.uplink
.send_async(Packet::new(
crate::crazyflie::SUPERVISOR_PORT,
SUPERVISOR_CH_COMMAND,
vec![CMD_ARM_SYSTEM, command],
))
.await?;
Ok(())
}
#[deprecated(since = "0.8.1", note = "Use [`Supervisor::send_crash_recovery_request`](crate::subsystems::supervisor::Supervisor::send_crash_recovery_request) instead")]
pub async fn send_crash_recovery_request(&self) -> Result<()> {
self.uplink
.send_async(Packet::new(
crate::crazyflie::SUPERVISOR_PORT,
SUPERVISOR_CH_COMMAND,
vec![CMD_RECOVER_SYSTEM],
))
.await?;
Ok(())
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct AppChannelPacket(Vec<u8>);
impl TryFrom<Vec<u8>> for AppChannelPacket {
type Error = Error;
fn try_from(value: Vec<u8>) -> Result<Self> {
if value.len() <= APPCHANNEL_MTU {
Ok(AppChannelPacket(value))
} else {
Err(Error::AppchannelPacketTooLarge)
}
}
}
impl TryFrom<&[u8]> for AppChannelPacket {
type Error = Error;
fn try_from(value: &[u8]) -> Result<Self> {
if value.len() <= APPCHANNEL_MTU {
Ok(AppChannelPacket(value.to_vec()))
} else {
Err(Error::AppchannelPacketTooLarge)
}
}
}
impl From<AppChannelPacket> for Vec<u8> {
fn from(pk: AppChannelPacket) -> Self {
pk.0
}
}
macro_rules! from_impl {
($n:expr_2021) => {
impl From<[u8; $n]> for AppChannelPacket {
fn from(v: [u8; $n]) -> Self {
AppChannelPacket(v.to_vec())
}
}
};
}
from_impl!(0);
from_impl!(1);
from_impl!(2);
from_impl!(3);
from_impl!(4);
from_impl!(5);
from_impl!(6);
from_impl!(7);
from_impl!(8);
from_impl!(9);
from_impl!(10);
from_impl!(11);
from_impl!(12);
from_impl!(13);
from_impl!(14);
from_impl!(15);
from_impl!(16);
from_impl!(17);
from_impl!(18);
from_impl!(19);
from_impl!(20);
from_impl!(21);
from_impl!(22);
from_impl!(23);
from_impl!(24);
from_impl!(25);
from_impl!(26);
from_impl!(27);
from_impl!(28);
from_impl!(29);
from_impl!(30);