Skip to content

Commit 38920e3

Browse files
authored
Implement Exclusive use of SharedCrazyradio and add WeakSharedCrazyradio (#5)
* Implement Exclusive use of SharedCrazyradio and add WeakSharedCrazyradio In order to handle multiple connection to radios and to be able to close the USB radio once all connections are dropped, the LinkContext was using Arc<SharedCrazyradio> and Weak<SharedCrazyradio>. This was not how the SharedCrazyradio was intended to be used, it was internded to be cloned to share the radio, not access by multiple unmutable references. This commit makes the SharedCrazyradio type encode this requirement by taking &mut self to most methods. It also adds a WeakSharedCrazyradio to handle the USB device management. The Crate version is bumped up since this is a breaking change. * Fix tests and example for new API * Run Cargo-fmt
1 parent 47af8f9 commit 38920e3

File tree

8 files changed

+132
-44
lines changed

8 files changed

+132
-44
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "crazyradio"
3-
version = "0.3.1"
3+
version = "0.4.0"
44
authors = ["Arnaud Taffanel <arnaud@taffanel.org>"]
55
edition = "2018"
66
description = "Crazyradio USB dongle driver"

examples/async_broadcast.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ use crazyradio::{Channel, Crazyradio, SharedCrazyradio};
33
#[tokio::main]
44
async fn main() -> Result<(), crazyradio::Error> {
55
let radio = Crazyradio::open_first_async().await?;
6-
let cr = SharedCrazyradio::new(radio);
6+
let mut cr = SharedCrazyradio::new(radio);
77

88
let channel = Channel::from_number(78).unwrap();
99
let address = [0xff, 0xe7, 0xe7, 0xe7, 0xe7];
10-
let payload = [0x8f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x40, 0x40];
10+
let payload = [
11+
0x8f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x40,
12+
0x40,
13+
];
1114

1215
// send a takeoff command via broadcast
13-
cr.send_packet_no_ack_async(channel, address, payload.to_vec()).await?;
16+
cr.send_packet_no_ack_async(channel, address, payload.to_vec())
17+
.await?;
1418

1519
Ok(())
1620
}

examples/async_scan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crazyradio::{Channel, Crazyradio, SharedCrazyradio};
33
#[tokio::main]
44
async fn main() -> Result<(), crazyradio::Error> {
55
let radio = Crazyradio::open_first_async().await?;
6-
let cr = SharedCrazyradio::new(radio);
6+
let mut cr = SharedCrazyradio::new(radio);
77

88
println!("Scanning channels from 0 to 125 ...");
99
let result = cr

examples/bandwidth_test.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ fn main() -> Result<(), crazyradio::Error> {
1818
let crtp_channel = 0;
1919
let header = ((crtp_port & 0x0F) << 4) | (crtp_channel & 0x0F);
2020
let payload_size = 28;
21-
let packet = vec![header as u8; payload_size+1]; // +1 for header byte
22-
21+
let packet = vec![header as u8; payload_size + 1]; // +1 for header byte
22+
2323
let mut n_ack = 0;
2424
let mut n_syslink = 0;
2525
let start = Instant::now();
@@ -30,7 +30,7 @@ fn main() -> Result<(), crazyradio::Error> {
3030
if ack.received {
3131
n_ack += 1;
3232

33-
if ack_data.len() > 2 && ack_data[0]&0xFC == 0xF0 {
33+
if ack_data.len() > 2 && ack_data[0] & 0xFC == 0xF0 {
3434
n_syslink += 1;
3535
}
3636
}
@@ -44,8 +44,15 @@ fn main() -> Result<(), crazyradio::Error> {
4444

4545
println!("Sent {} packets in {:.2} seconds", N_PACKETS, seconds);
4646
println!("Throughput: {:.2} packets/second", pps);
47-
println!("Packet success rate: {:.2}%", (n_ack as f64 / N_PACKETS as f64) * 100.0);
48-
println!("Syslink packet rate: {:.2}% ({} pk/s)", (n_syslink as f64 / N_PACKETS as f64) * 100.0, (n_syslink as f64 / seconds));
47+
println!(
48+
"Packet success rate: {:.2}%",
49+
(n_ack as f64 / N_PACKETS as f64) * 100.0
50+
);
51+
println!(
52+
"Syslink packet rate: {:.2}% ({} pk/s)",
53+
(n_syslink as f64 / N_PACKETS as f64) * 100.0,
54+
(n_syslink as f64 / seconds)
55+
);
4956

5057
Ok(())
5158
}

examples/broadcast.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ fn main() -> Result<(), crazyradio::Error> {
99
cr.set_ack_enable(false)?;
1010

1111
// send a takeoff command via broadcast
12-
cr.send_packet_no_ack(&[0x8f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x40, 0x40])?;
12+
cr.send_packet_no_ack(&[
13+
0x8f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x40,
14+
0x40,
15+
])?;
1316

1417
Ok(())
1518
}

examples/stress_setup.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crazyradio::{Channel, Crazyradio};
2-
use indicatif::{ProgressBar, HumanCount};
2+
use indicatif::{HumanCount, ProgressBar};
33

44
fn main() -> Result<(), crazyradio::Error> {
55
let mut cr = Crazyradio::open_first()?;
@@ -15,7 +15,7 @@ fn main() -> Result<(), crazyradio::Error> {
1515

1616
let mut i = 0;
1717
loop {
18-
i+=1;
18+
i += 1;
1919
for j in 0..100usize {
2020
// cr.set_channel(Channel::from_number(0)?)?;
2121
// cr.set_ack_enable(j.is_multiple_of(2))?;
@@ -29,7 +29,6 @@ fn main() -> Result<(), crazyradio::Error> {
2929
let mut ack_data = [0u8; 32];
3030
cr.send_packet(&[0xff], &mut ack_data)?;
3131
}
32-
3332
}
3433
pb.set_message(format!("Iterations: {} ({} loops)", i, HumanCount(i * 100)));
3534
pb.tick();

src/lib.rs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
//! - **async** enables async function to create a [Crazyradio] object and use the [SharedCrazyradio]
1111
//! - **serde** emables [serde](https://crates.io/crates/serde) serialization/deserialization of the [Channel] struct
1212
13+
#![deny(missing_docs)]
14+
1315
#[cfg(feature = "shared_radio")]
1416
mod shared_radio;
1517
#[cfg(feature = "shared_radio")]
16-
pub use crate::shared_radio::SharedCrazyradio;
18+
pub use crate::shared_radio::{SharedCrazyradio, WeakSharedCrazyradio};
1719

1820
use core::time::Duration;
1921
#[cfg(feature = "serde_support")]
@@ -451,15 +453,15 @@ impl Crazyradio {
451453
}
452454

453455
/// Set inline-settings USB protocol mode
454-
///
456+
///
455457
/// When this mode is enabled, setting channel, datarate, address and
456458
/// ack_enable will become cached operations, and these settings
457459
/// will be sent as header to the data over USB. This increases performance
458460
/// when communicating with more than one PRX.
459-
///
461+
///
460462
/// This mode, if available, is activated by default when creating the Crazyradio
461463
/// object.
462-
///
464+
///
463465
/// This mode is only available with Crazyradio 2.0+
464466
pub fn set_inline_mode(&mut self, inline_mode_enable: bool) -> Result<()> {
465467
let setting = inline_mode_enable.then_some(1).unwrap_or(0);
@@ -478,8 +480,12 @@ impl Crazyradio {
478480
}
479481

480482
/// Set packet loss simulation.
481-
///
482-
pub fn set_packet_loss_simulation(&mut self, packet_loss_percent: u8, ack_loss_percent: u8) -> Result<()> {
483+
///
484+
pub fn set_packet_loss_simulation(
485+
&mut self,
486+
packet_loss_percent: u8,
487+
ack_loss_percent: u8,
488+
) -> Result<()> {
483489
if self.device_desciptor.device_version() < rusb::Version::from_bcd(0x0500) {
484490
return Err(Error::DongleVersionNotSupported);
485491
}
@@ -511,7 +517,6 @@ impl Crazyradio {
511517
/// be truncated. The length of the ack payload is returned
512518
/// in Ack::length.
513519
pub fn send_packet(&mut self, data: &[u8], ack_data: &mut [u8]) -> Result<Ack> {
514-
515520
if self.inline_mode {
516521
self.send_inline(data, Some(ack_data))
517522
} else {
@@ -538,7 +543,6 @@ impl Crazyradio {
538543
length: received - 1,
539544
})
540545
}
541-
542546
}
543547

544548
/// Send a data packet without caring for Ack (for broadcast communication).
@@ -558,7 +562,7 @@ impl Crazyradio {
558562
}
559563

560564
fn send_inline(&mut self, data: &[u8], ack_data: Option<&mut [u8]>) -> Result<Ack> {
561-
const OUT_HEADER_LENGTH: usize=8;
565+
const OUT_HEADER_LENGTH: usize = 8;
562566
const IN_HEADER_LENGTH: usize = 2;
563567

564568
const OUT_FIELD2_ACK_ENABLE: u8 = 0x10;
@@ -582,21 +586,24 @@ impl Crazyradio {
582586
command.extend_from_slice(&data);
583587

584588
let mut answer = [0u8; 64];
585-
self.device_handle.write_bulk(0x01, &command, Duration::from_secs(1))?;
586-
self.device_handle.read_bulk(0x81, &mut answer, Duration::from_secs(1))?;
589+
self.device_handle
590+
.write_bulk(0x01, &command, Duration::from_secs(1))?;
591+
self.device_handle
592+
.read_bulk(0x81, &mut answer, Duration::from_secs(1))?;
587593

588594
// Decode answer
589595
let payload_length = (answer[0] as usize) - 2;
590596
if let Some(ack_data) = ack_data {
591-
ack_data[0..payload_length].copy_from_slice(&answer[IN_HEADER_LENGTH..(IN_HEADER_LENGTH+payload_length)]);
597+
ack_data[0..payload_length]
598+
.copy_from_slice(&answer[IN_HEADER_LENGTH..(IN_HEADER_LENGTH + payload_length)]);
592599
}
593600

594601
Ok(Ack {
595-
received: answer[1] & IN_HEADER_ACK_RECEIVED != 0,
596-
power_detector: answer[1] & IN_HEADER_POWER_DETECTOR != 0,
597-
retry: ((answer[1] & IN_HEADER_RETRY_MASK) >> IN_HEADER_RETRY_SHIFT) as usize,
598-
length: payload_length,
599-
})
602+
received: answer[1] & IN_HEADER_ACK_RECEIVED != 0,
603+
power_detector: answer[1] & IN_HEADER_POWER_DETECTOR != 0,
604+
retry: ((answer[1] & IN_HEADER_RETRY_MASK) >> IN_HEADER_RETRY_SHIFT) as usize,
605+
length: payload_length,
606+
})
600607
}
601608
}
602609

@@ -611,7 +618,6 @@ impl Crazyradio {
611618
#[cfg(feature = "async")]
612619
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
613620
impl Crazyradio {
614-
615621
/// Async vesion of [Crazyradio::open_first()]
616622
pub async fn open_first_async() -> Result<Self> {
617623
let (tx, rx) = flume::bounded(0);
@@ -651,14 +657,19 @@ impl Crazyradio {
651657
}
652658
}
653659

660+
/// Errors returned by Crazyradio functions
654661
#[derive(thiserror::Error, Debug, Clone)]
655662
pub enum Error {
656-
#[error("Usb Error: {0}:?")]
663+
/// USB error returned by the underlying rusb library
664+
#[error("Usb Error: {0:?}")]
657665
UsbError(rusb::Error),
666+
/// Crazyradio not found
658667
#[error("Crazyradio not found")]
659668
NotFound,
669+
/// Invalid argument passed to function
660670
#[error("Invalid arguments")]
661671
InvalidArgument,
672+
/// Crazyradio version not supported
662673
#[error("Crazyradio version not supported")]
663674
DongleVersionNotSupported,
664675
}
@@ -701,6 +712,9 @@ impl<'de> Deserialize<'de> for Channel {
701712
}
702713

703714
impl Channel {
715+
/// Create a Channel from its number (0-125)
716+
///
717+
/// Returns an Error::InvalidArgument if the channel number is out of range
704718
pub fn from_number(channel: u8) -> Result<Self> {
705719
if channel < 126 {
706720
Ok(Channel(channel))
@@ -719,16 +733,23 @@ impl From<Channel> for u8 {
719733
/// Radio datarate
720734
#[derive(Copy, Clone, PartialEq)]
721735
pub enum Datarate {
736+
/// 250 kbps
722737
Dr250K = 0,
738+
/// 1 Mbps
723739
Dr1M = 1,
740+
/// 2 Mbps
724741
Dr2M = 2,
725742
}
726743

727744
/// Radio power
728745
pub enum Power {
746+
/// -18 dBm
729747
Pm18dBm = 0,
748+
/// -12 dBm
730749
Pm12dBm = 1,
750+
/// -6 dBm
731751
Pm6dBm = 2,
752+
/// 0 dBm
732753
P0dBm = 3,
733754
}
734755

0 commit comments

Comments
 (0)