Skip to content

Commit baca7eb

Browse files
committed
Added functionality to send data for forwarding to wireshark
1 parent 47af8f9 commit baca7eb

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ tokio = { version = "1.6.1", features = ["rt", "rt-multi-thread","macros"] }
3030
serde_support = ["serde"]
3131
shared_radio = ["flume"]
3232
async = ["flume/async"]
33+
wireshark = []
3334

3435
[package.metadata.docs.rs]
3536
all-features = true

src/capture.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//! Wireshark packet capture support for Crazyradio
2+
//!
3+
//! This module provides a callback mechanism for capturing packets
4+
//! sent and received via the Crazyradio.
5+
6+
use std::sync::{Mutex, OnceLock};
7+
8+
/// Direction: transmit (to device)
9+
pub const DIRECTION_TX: u8 = 0;
10+
/// Direction: receive (from device)
11+
pub const DIRECTION_RX: u8 = 1;
12+
13+
/// Packet capture callback type
14+
///
15+
/// Arguments: (direction, channel, address, radio_index, data)
16+
pub type CaptureCallback = Box<dyn Fn(u8, u8, &[u8; 5], u8, &[u8]) + Send + Sync>;
17+
18+
/// Global capture callback
19+
static CAPTURE_CALLBACK: OnceLock<Mutex<Option<CaptureCallback>>> = OnceLock::new();
20+
21+
/// Set the packet capture callback
22+
///
23+
/// This should be called once at initialization to enable packet capture.
24+
/// The callback will be invoked for every packet sent or received.
25+
pub fn set_callback(callback: CaptureCallback) {
26+
let cb = CAPTURE_CALLBACK.get_or_init(|| Mutex::new(None));
27+
if let Ok(mut guard) = cb.lock() {
28+
*guard = Some(callback);
29+
}
30+
}
31+
32+
/// Clear the packet capture callback
33+
pub fn clear_callback() {
34+
if let Some(cb) = CAPTURE_CALLBACK.get() {
35+
if let Ok(mut guard) = cb.lock() {
36+
*guard = None;
37+
}
38+
}
39+
}
40+
41+
/// Send a packet to the capture callback (if set)
42+
pub(crate) fn capture_packet(direction: u8, channel: u8, address: &[u8; 5], radio_index: u8, data: &[u8]) {
43+
if let Some(cb) = CAPTURE_CALLBACK.get() {
44+
if let Ok(guard) = cb.lock() {
45+
if let Some(ref callback) = *guard {
46+
callback(direction, channel, address, radio_index, data);
47+
}
48+
}
49+
}
50+
}

src/lib.rs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ mod shared_radio;
1515
#[cfg(feature = "shared_radio")]
1616
pub use crate::shared_radio::SharedCrazyradio;
1717

18+
#[cfg(feature = "wireshark")]
19+
pub mod capture;
20+
1821
use core::time::Duration;
1922
#[cfg(feature = "serde_support")]
2023
use serde::{Deserialize, Serialize};
@@ -136,6 +139,10 @@ pub struct Crazyradio {
136139
address: [u8; 5],
137140
datarate: Datarate,
138141
ack_enable: bool,
142+
143+
/// Radio index (for capture identification)
144+
#[cfg(feature = "wireshark")]
145+
radio_index: u8,
139146
}
140147

141148
impl Crazyradio {
@@ -200,6 +207,9 @@ impl Crazyradio {
200207
datarate: Datarate::Dr2M,
201208

202209
ack_enable: true,
210+
211+
#[cfg(feature = "wireshark")]
212+
radio_index: nth.unwrap_or(0) as u8,
203213
};
204214

205215
cr.reset()?;
@@ -511,9 +521,18 @@ impl Crazyradio {
511521
/// be truncated. The length of the ack payload is returned
512522
/// in Ack::length.
513523
pub fn send_packet(&mut self, data: &[u8], ack_data: &mut [u8]) -> Result<Ack> {
514-
515-
if self.inline_mode {
516-
self.send_inline(data, Some(ack_data))
524+
// Capture TX packet
525+
#[cfg(feature = "wireshark")]
526+
capture::capture_packet(
527+
capture::DIRECTION_TX,
528+
self.channel.into(),
529+
&self.address,
530+
self.radio_index,
531+
data,
532+
);
533+
534+
let ack = if self.inline_mode {
535+
self.send_inline(data, Some(ack_data))?
517536
} else {
518537
self.device_handle
519538
.write_bulk(0x01, data, Duration::from_secs(1))?;
@@ -531,14 +550,27 @@ impl Crazyradio {
531550
.copy_from_slice(&received_data[1..33]);
532551
}
533552

534-
Ok(Ack {
553+
Ack {
535554
received: received_data[0] & 0x01 != 0,
536555
power_detector: received_data[0] & 0x02 != 0,
537556
retry: ((received_data[0] & 0xf0) >> 4) as usize,
538557
length: received - 1,
539-
})
558+
}
559+
};
560+
561+
// Capture RX packet (ACK payload)
562+
#[cfg(feature = "wireshark")]
563+
if ack.received && ack.length > 0 {
564+
capture::capture_packet(
565+
capture::DIRECTION_RX,
566+
self.channel.into(),
567+
&self.address,
568+
self.radio_index,
569+
&ack_data[..ack.length],
570+
);
540571
}
541-
572+
573+
Ok(ack)
542574
}
543575

544576
/// Send a data packet without caring for Ack (for broadcast communication).
@@ -547,6 +579,16 @@ impl Crazyradio {
547579
///
548580
/// * `data`: Up to 32 bytes of data to be send.
549581
pub fn send_packet_no_ack(&mut self, data: &[u8]) -> Result<()> {
582+
// Capture TX packet
583+
#[cfg(feature = "wireshark")]
584+
capture::capture_packet(
585+
capture::DIRECTION_TX,
586+
self.channel.into(),
587+
&self.address,
588+
self.radio_index,
589+
data,
590+
);
591+
550592
if self.inline_mode {
551593
self.send_inline(data, None)?;
552594
} else {

0 commit comments

Comments
 (0)