crazyflie_link/
context.rs

1//! # Link Context
2//!
3//! The Link context keeps track of the radio dongles opened and used by connections.
4//! It also keeps track of the async executor
5
6use crate::connection::Connection;
7use crate::connection::ConnectionTrait;
8use crate::crazyflie_usb_connection::CrazyflieUSBConnection;
9use crate::crazyradio::SharedCrazyradio;
10use crate::crazyradio_connection::CrazyradioConnection;
11use crate::error::{Error, Result};
12use futures_util::lock::Mutex;
13
14use std::collections::BTreeMap;
15use std::sync::{Arc, Weak};
16
17/// Context for the link connections
18pub struct LinkContext {
19    radios: Mutex<BTreeMap<usize, Weak<SharedCrazyradio>>>,
20}
21
22impl LinkContext {
23    /// Create a new link context
24    pub fn new() -> Self {
25        Self {
26            radios: Mutex::new(BTreeMap::new()),
27        }
28    }
29
30    pub(crate) async fn get_radio(&self, radio_nth: usize) -> Result<Arc<SharedCrazyradio>> {
31        let mut radios = self.radios.lock().await;
32
33        radios.entry(radio_nth).or_insert_with(Weak::new);
34
35        let radio = match Weak::upgrade(&radios[&radio_nth]) {
36            Some(radio) => radio,
37            None => {
38                let new_radio = crate::crazyradio::Crazyradio::open_nth_async(radio_nth).await?;
39                let new_radio = Arc::new(SharedCrazyradio::new(new_radio));
40                radios.insert(radio_nth, Arc::downgrade(&new_radio));
41
42                new_radio
43            }
44        };
45        Ok(radio)
46    }
47
48    /// Scan for Crazyflies at some given address
49    ///
50    /// This function will send a packet to every channels and look for an acknowledgement in return.
51    ///
52    /// The address argument will set the radio packets address to scan for.
53    ///
54    /// It returns a list of URIs that can be passed to the [LinkContext::open_link()] function.
55    pub async fn scan(&self, address: [u8; 5]) -> Result<Vec<String>> {
56        let mut found = Vec::new();
57
58        found.extend(CrazyradioConnection::scan(self, address).await?);
59        found.extend(CrazyflieUSBConnection::scan().await?);
60
61        Ok(found)
62    }
63
64    /// Scan for a given list of URIs
65    ///
66    /// Send a packet to each URI and detect if an acknowledgement is sent back.
67    ///
68    /// Returns the list of URIs that acknowledged
69    pub async fn scan_selected(&self, uris: Vec<&str>) -> Result<Vec<String>> {
70        let mut found = Vec::new();
71
72        found.extend(CrazyradioConnection::scan_selected(self, uris.clone()).await?);
73        found.extend(CrazyflieUSBConnection::scan_selected(uris).await?);
74
75        Ok(found)
76    }
77
78    /// Open a link connection to a given URI
79    ///
80    /// If successful, the link [Connection] is returned.
81    pub async fn open_link(&self, uri: &str) -> Result<Connection> {
82        let connection: Option<Box<dyn ConnectionTrait + Send + Sync>> =
83            if let Some(connection) = CrazyradioConnection::open(self, uri).await? {
84                Some(Box::new(connection))
85            } else if let Some(connection) = CrazyflieUSBConnection::open(self, uri).await? {
86                Some(Box::new(connection))
87            } else {
88                None
89            };
90
91        let internal_connection = connection.ok_or(Error::InvalidUri)?;
92
93        Ok(Connection::new(internal_connection))
94    }
95}