Skip to content

Commit 43dc1ae

Browse files
authored
Implemented radio broadcast (#10)
1 parent ab6ece1 commit 43dc1ae

4 files changed

Lines changed: 57 additions & 7 deletions

File tree

cflib2/_rust.pyi

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,24 @@ class LinkContext:
841841
# Returns
842842
List of URIs found
843843
"""
844+
async def send_radio_broadcast(
845+
self,
846+
radio_nth: builtins.int,
847+
channel: builtins.int,
848+
address: typing.Sequence[builtins.int],
849+
data: typing.Sequence[builtins.int],
850+
) -> None:
851+
r"""
852+
Send a radio broadcast packet (no acknowledgement) on a specific radio and channel
853+
854+
This sends a raw packet without expecting an ack, useful for P2P communication.
855+
856+
# Arguments
857+
* `radio_nth` - Radio dongle index (usually 0)
858+
* `channel` - Radio channel number (0-125)
859+
* `address` - 5-byte destination address
860+
* `data` - Packet payload bytes
861+
"""
844862

845863
class LinkError(CrazyflieError):
846864
r"""

rust/Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ extension-module = ["pyo3/extension-module"]
1515
pyo3 = { version = "0.26" }
1616
pyo3-async-runtimes = { version = "0.26", features = ["tokio-runtime"] }
1717
crazyflie-lib = "0.7.1"
18-
crazyflie-link = "0.4.2"
18+
crazyflie-link = "0.4.3"
19+
crazyradio = "0.6.0"
1920
tokio = { version = "1.48", features = ["full"] }
2021
futures = "0.3.31"
2122
pyo3-stub-gen-derive = "0.17.0"

rust/src/link_context.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
//! Link context for scanning and discovering Crazyflies
2323
2424
use pyo3::prelude::*;
25-
use pyo3::exceptions::PyRuntimeError;
25+
use pyo3::exceptions::{PyRuntimeError, PyValueError};
2626
use pyo3_stub_gen_derive::*;
2727
use std::sync::Arc;
2828

@@ -65,7 +65,7 @@ impl LinkContext {
6565
// Default to E7E7E7E7E7 if no address provided
6666
let addr = if let Some(addr_vec) = address {
6767
if addr_vec.len() != 5 {
68-
return Err(PyRuntimeError::new_err(
68+
return Err(PyValueError::new_err(
6969
"Address must be exactly 5 bytes"
7070
));
7171
}
@@ -83,4 +83,34 @@ impl LinkContext {
8383
Ok(uris.into_iter().map(|uri| uri.to_string()).collect::<Vec<_>>())
8484
})
8585
}
86+
87+
/// Send a radio broadcast packet (no acknowledgement) on a specific radio and channel
88+
///
89+
/// This sends a raw packet without expecting an ack, useful for P2P communication.
90+
///
91+
/// # Arguments
92+
/// * `radio_nth` - Radio dongle index (usually 0)
93+
/// * `channel` - Radio channel number (0-125)
94+
/// * `address` - 5-byte destination address
95+
/// * `data` - Packet payload bytes
96+
#[gen_stub(override_return_type(type_repr = "collections.abc.Coroutine[typing.Any, typing.Any, None]"))]
97+
fn send_radio_broadcast<'py>(&self, py: Python<'py>, radio_nth: usize, channel: u8, address: Vec<u8>, data: Vec<u8>) -> PyResult<Bound<'py, PyAny>> {
98+
if address.len() != 5 {
99+
return Err(PyValueError::new_err("Address must be exactly 5 bytes"));
100+
}
101+
let mut addr_array = [0u8; 5];
102+
addr_array.copy_from_slice(&address);
103+
104+
let ch = crazyradio::Channel::from_number(channel)
105+
.map_err(|_| PyValueError::new_err(format!("Invalid channel {}: must be 0-125", channel)))?;
106+
107+
let inner = self.inner.clone();
108+
pyo3_async_runtimes::tokio::future_into_py(py, async move {
109+
let mut radio = inner.get_radio(radio_nth).await
110+
.map_err(|e| PyRuntimeError::new_err(format!("Failed to get radio: {:?}", e)))?;
111+
radio.send_packet_no_ack_async(ch, addr_array, data).await
112+
.map_err(|e| PyRuntimeError::new_err(format!("Broadcast failed: {:?}", e)))?;
113+
Ok(())
114+
})
115+
}
86116
}

0 commit comments

Comments
 (0)