mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-29 21:30:39 +00:00

* [esp-metadata] Remove lazy_static in favor of OnceLock * [esp-wifishark] Remove lazy_static in favor of normal initialisation * [ieee802154-sniffer] Shorten SelectorConfig initialisation * [ieee802154-sniffer] Remove lazy_static in favor of normal initialisation
244 lines
8.2 KiB
Rust
244 lines
8.2 KiB
Rust
use std::{
|
|
io::{stdout, BufRead, BufReader, Write},
|
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
|
};
|
|
|
|
use clap::Parser;
|
|
use pcap_file::{
|
|
pcap::{PcapHeader, PcapPacket, PcapWriter},
|
|
DataLink,
|
|
};
|
|
use r_extcap::{
|
|
config::{ConfigOptionValue, SelectorConfig, StringConfig},
|
|
controls::{synchronous::ExtcapControlSender, ControlCommand, ControlPacket},
|
|
interface::{Dlt, Interface, Metadata},
|
|
ExtcapStep,
|
|
};
|
|
|
|
#[derive(Debug, Parser)]
|
|
pub struct AppArgs {
|
|
#[command(flatten)]
|
|
extcap: r_extcap::ExtcapArgs,
|
|
|
|
#[arg(long, default_value = "")]
|
|
serialport: String,
|
|
|
|
#[arg(long, default_value = "11")]
|
|
channel: String,
|
|
}
|
|
|
|
fn config_option_value(value: &'static str) -> ConfigOptionValue {
|
|
ConfigOptionValue::builder()
|
|
.value(value)
|
|
.display(value)
|
|
.build()
|
|
}
|
|
|
|
fn main() {
|
|
let args = AppArgs::parse();
|
|
|
|
if !args.extcap.capture {
|
|
if let Some(_filter) = args.extcap.extcap_capture_filter {
|
|
std::process::exit(0);
|
|
}
|
|
}
|
|
|
|
let wifi_capture_interface = Interface {
|
|
value: "802.15.4".into(),
|
|
display: "esp-ieee802154 Sniffer".into(),
|
|
dlt: Dlt {
|
|
data_link_type: DataLink::USER0,
|
|
name: "USER0".into(),
|
|
display: "IEEE802.15.4".into(),
|
|
},
|
|
};
|
|
|
|
match args.extcap.run().unwrap() {
|
|
ExtcapStep::Interfaces(interfaces_step) => {
|
|
let metadata = Metadata {
|
|
help_url: "http://github.com/esp-rs".into(),
|
|
display_description: "esp-ieee802154".into(),
|
|
..r_extcap::cargo_metadata!()
|
|
};
|
|
|
|
interfaces_step.list_interfaces(&metadata, &[&wifi_capture_interface], &[]);
|
|
}
|
|
ExtcapStep::Dlts(dlts_step) => {
|
|
dlts_step
|
|
.print_from_interfaces(&[&wifi_capture_interface])
|
|
.unwrap();
|
|
}
|
|
ExtcapStep::Config(config_step) => {
|
|
let config_serialport = StringConfig::builder()
|
|
.config_number(1)
|
|
.call("serialport")
|
|
.display("Serialport")
|
|
.tooltip("Serialport to connect to")
|
|
.required(false)
|
|
.placeholder("")
|
|
.build();
|
|
|
|
let config_channel = SelectorConfig::builder()
|
|
.config_number(3)
|
|
.call("channel")
|
|
.display("Channel")
|
|
.tooltip("Channel Selector")
|
|
.default_options([
|
|
ConfigOptionValue::builder()
|
|
.value("11")
|
|
.display("11")
|
|
.default(true)
|
|
.build(),
|
|
config_option_value("12"),
|
|
config_option_value("13"),
|
|
config_option_value("14"),
|
|
config_option_value("15"),
|
|
config_option_value("16"),
|
|
config_option_value("17"),
|
|
config_option_value("18"),
|
|
config_option_value("19"),
|
|
config_option_value("20"),
|
|
config_option_value("21"),
|
|
config_option_value("22"),
|
|
config_option_value("23"),
|
|
config_option_value("24"),
|
|
config_option_value("25"),
|
|
config_option_value("26"),
|
|
])
|
|
.build();
|
|
|
|
config_step.list_configs(&[&config_serialport, &config_channel])
|
|
}
|
|
ExtcapStep::ReloadConfig(_reload_config_step) => {
|
|
panic!("Unsupported operation");
|
|
}
|
|
ExtcapStep::Capture(capture_step) => {
|
|
let (data_link, prefix) = (DataLink::IEEE802_15_4, "@RAW [");
|
|
|
|
let mut controls = (
|
|
capture_step.spawn_channel_control_reader(),
|
|
capture_step.new_control_sender(),
|
|
);
|
|
|
|
if let (Some(control_reader), Some(_control_sender)) = &mut controls {
|
|
let packet = control_reader.read_packet().unwrap();
|
|
assert_eq!(packet.command, ControlCommand::Initialized);
|
|
}
|
|
|
|
let pcap_header = PcapHeader {
|
|
datalink: data_link,
|
|
endianness: pcap_file::Endianness::Big,
|
|
..Default::default()
|
|
};
|
|
let mut pcap_writer = PcapWriter::with_header(capture_step.fifo, pcap_header).unwrap();
|
|
|
|
let channel = args.channel.clone();
|
|
|
|
let serialport = if args.serialport.is_empty() {
|
|
let ports = serialport::available_ports().unwrap();
|
|
if ports.len() != 1 {
|
|
panic!("There are more or less than one serial ports. Don't know which one to use.");
|
|
}
|
|
ports[0].port_name.clone()
|
|
} else {
|
|
args.serialport.clone()
|
|
};
|
|
|
|
let mut port = serialport::new(serialport, 115_200)
|
|
.timeout(Duration::from_millis(100))
|
|
.open()
|
|
.expect("Failed to open port");
|
|
|
|
// drain the input ... just to be on the safe side
|
|
while let Ok(len) = port.read(&mut [0u8; 128]) {
|
|
if len == 0 {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// maybe reset the target
|
|
port.write_all(&[b'r']).unwrap();
|
|
|
|
// wait for target to boot up
|
|
std::thread::sleep(Duration::from_millis(1000));
|
|
|
|
// configure channel
|
|
port.write_all(format!("{:02}", (channel).parse::<u16>().unwrap()).as_bytes())
|
|
.unwrap();
|
|
|
|
let mut buf_read = BufReader::new(port);
|
|
|
|
let mut packet = Vec::<u8>::new();
|
|
let mut line = String::new();
|
|
|
|
loop {
|
|
if let (Some(control_reader), Some(control_sender)) = &mut controls {
|
|
if let Some(control_packet) = control_reader.try_read_packet() {
|
|
handle_control_packet(&control_packet, control_sender).unwrap();
|
|
}
|
|
}
|
|
|
|
packet.clear();
|
|
line.clear();
|
|
if let Ok(len) = buf_read.read_line(&mut line) {
|
|
if len > 0 {
|
|
if line.contains(prefix) {
|
|
if !line.contains(']') {
|
|
panic!("Unexpected {}", line);
|
|
}
|
|
|
|
let start = line.find(prefix).unwrap() + prefix.len();
|
|
let end = line.find(']').unwrap();
|
|
let line = line[start..end].to_string();
|
|
for hex in line.split(", ") {
|
|
let byte = u8::from_str_radix(hex, 16).unwrap();
|
|
packet.push(byte);
|
|
}
|
|
}
|
|
|
|
if !packet.is_empty() {
|
|
let len = packet[0] - 2;
|
|
let crc = crc(&packet[1..][..len as usize]);
|
|
packet.insert(1 + (len as usize), crc[0]);
|
|
packet.insert(1 + (len as usize) + 1, crc[1]);
|
|
|
|
pcap_writer
|
|
.write_packet(&PcapPacket::new(
|
|
SystemTime::now().duration_since(UNIX_EPOCH).unwrap(),
|
|
(len as u32) + 2,
|
|
&packet[1..][..(len + 2) as usize],
|
|
))
|
|
.unwrap();
|
|
}
|
|
stdout().flush().unwrap();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
fn crc(buf: &[u8]) -> [u8; 2] {
|
|
let mut c: u16 = 0;
|
|
for &i in buf {
|
|
for k in 0..8 {
|
|
let b = ((i & (1 << k)) != 0) ^ ((c & 1) != 0);
|
|
c >>= 1;
|
|
if b {
|
|
c ^= 1 << 15;
|
|
c ^= 1 << 10;
|
|
c ^= 1 << 3;
|
|
}
|
|
}
|
|
}
|
|
[((c & 0xFF) as u8), ((c >> 8) as u8)]
|
|
}
|
|
|
|
fn handle_control_packet(
|
|
_control_packet: &ControlPacket<'_>,
|
|
_control_sender: &mut ExtcapControlSender,
|
|
) -> Result<(), ()> {
|
|
// currently nothing to do here
|
|
Ok(())
|
|
}
|