crazyflie_lib/
crazyflie.rs1use crate::subsystems::commander::Commander;
2use crate::subsystems::console::Console;
3use crate::subsystems::log::Log;
4use crate::subsystems::param::Param;
5
6use crate::crtp_utils::CrtpDispatch;
7use crate::subsystems::platform::Platform;
8use crate::{Error, Result};
9use crate::SUPPORTED_PROTOCOL_VERSION;
10use flume as channel;
11use futures::lock::Mutex;
12use tokio::task::JoinHandle;
13use std::sync::atomic::AtomicBool;
14use std::sync::atomic::Ordering::Relaxed;
15use std::sync::Arc;
16use std::time::Duration;
17
18pub(crate) const CONSOLE_PORT: u8 = 0;
20pub(crate) const PARAM_PORT: u8 = 2;
21pub(crate) const COMMANDER_PORT: u8 = 3;
22pub(crate) const _MEMORY_PORT: u8 = 4;
23pub(crate) const LOG_PORT: u8 = 5;
24pub(crate) const _LOCALIZATION_PORT: u8 = 6;
25pub(crate) const _GENERIC_SETPOINT_PORT: u8 = 7;
26pub(crate) const PLATFORM_PORT: u8 = 13;
27pub(crate) const _LINK_PORT: u8 = 15;
28
29pub struct Crazyflie {
37 pub log: Log,
39 pub param: Param,
41 pub commander: Commander,
43 pub console: Console,
45 pub platform: Platform,
47 uplink_task: Mutex<Option<JoinHandle<()>>>,
48 dispatch_task: Mutex<Option<JoinHandle<()>>>,
49 disconnect: Arc<AtomicBool>,
50 link: Arc<crazyflie_link::Connection>,
51}
52
53impl Crazyflie {
54 pub async fn connect_from_uri(
63 link_context: &crazyflie_link::LinkContext,
64 uri: &str,
65 ) -> Result<Self> {
66 let link = link_context.open_link(uri).await?;
67
68 Self::connect_from_link(link).await
69 }
70
71 pub async fn connect_from_link(
80 link: crazyflie_link::Connection,
81 ) -> Result<Self> {
82 let disconnect = Arc::new(AtomicBool::new(false));
83
84 let link = Arc::new(link);
86 let mut dispatcher = CrtpDispatch::new(link.clone(), disconnect.clone());
87
88 let disconnect_uplink = disconnect.clone();
90 let (uplink, rx) = channel::unbounded();
91 let link_uplink = link.clone();
92 let uplink_task = tokio::spawn(async move {
93 while !disconnect_uplink.load(Relaxed) {
94 match tokio::time::timeout(
95 Duration::from_millis(100), rx.recv_async()
96 ).await
97 {
98 Ok(Ok(pk)) => {
99 if link_uplink.send_packet(pk).await.is_err() {
100 return;
101 }
102 }
103 Err(_) => (),
104 Ok(Err(flume::RecvError::Disconnected)) => return,
105 }
106 }
107 });
108
109 let platform_downlink = dispatcher.get_port_receiver(PLATFORM_PORT).unwrap();
111 let log_downlink = dispatcher.get_port_receiver(LOG_PORT).unwrap();
112 let param_downlink = dispatcher.get_port_receiver(PARAM_PORT).unwrap();
113 let console_downlink = dispatcher.get_port_receiver(CONSOLE_PORT).unwrap();
114
115 let dispatch_task = dispatcher.run().await?;
117
118 let platform = Platform::new(uplink.clone(), platform_downlink);
120
121 let protocol_version = platform.protocol_version().await?;
122
123 if !(SUPPORTED_PROTOCOL_VERSION..=(SUPPORTED_PROTOCOL_VERSION + 1))
124 .contains(&protocol_version)
125 {
126 return Err(Error::ProtocolVersionNotSupported);
127 }
128
129 let log_future = Log::new(log_downlink, uplink.clone());
133 let param_future = Param::new(param_downlink, uplink.clone());
134
135 let commander = Commander::new(uplink.clone());
136 let console = Console::new(console_downlink).await?;
137
138 let (log, param) = futures::join!(log_future, param_future);
140
141 Ok(Crazyflie {
142 log: log?,
143 param: param?,
144 commander,
145 console,
146 platform,
147 uplink_task: Mutex::new(Some(uplink_task)),
148 dispatch_task: Mutex::new(Some(dispatch_task)),
149 disconnect,
150 link,
151 })
152 }
153
154 pub async fn disconnect(&self) {
162 self.disconnect.store(true, Relaxed);
164
165 if let Some(uplink_task) = self.uplink_task.lock().await.take() {
167 uplink_task.await.expect("Uplink task failed");
168 }
169 if let Some(dispatch_task) = self.dispatch_task.lock().await.take() {
170 dispatch_task.await.expect("Dispatcher task failed");
171 }
172
173 self.link.close().await;
174 }
175
176 pub async fn wait_disconnect(&self) -> String {
184 let reason = self.link.wait_close().await;
185
186 self.disconnect().await;
187
188 reason
189 }
190}
191
192impl Drop for Crazyflie {
193 fn drop(&mut self) {
194 self.disconnect.store(true, Relaxed);
195 }
196}