Updated adsb stuff

This commit is contained in:
2025-04-23 19:20:30 -04:00
parent 1ce5e61ae3
commit 3b5514e825
12 changed files with 128 additions and 100 deletions

View File

@@ -1,8 +1,8 @@
[workspace]
members = [
"adsb_lib",
"adsb_recv",
"adsb_sim"
"squawk",
"squawk_sim"
]
resolver = "2"
package.version = "0.1.0"

View File

@@ -141,7 +141,7 @@ impl TryFrom<u8> for Capability {
return Err(Error::new(
ErrorKind::InvalidData,
format!("invalid CA value: {}", value),
))
));
}
};
Ok(capability)
@@ -164,9 +164,8 @@ impl TryFrom<u8> for Capability {
pub enum ADSBMessage {
AircraftIdentification(AircraftIdentification),
SurfacePosition(SurfacePosition),
AirbornePositionBaro(AirbornePositionBaro),
AirbornePosition(AirbornePosition),
AirborneVelocities(AirborneVelocities),
AirbornePositionGNSS(AirbornePositionGNSS),
Reserved(u8),
AircraftStatus(AircraftStatus),
TargetState(TargetState),
@@ -188,9 +187,9 @@ impl ADSBMessage {
ADSBMessage::AircraftIdentification(AircraftIdentification::decode(type_code, data)?)
}
5..=8 => ADSBMessage::SurfacePosition(SurfacePosition::decode(data)?),
9..=18 => ADSBMessage::AirbornePositionBaro(AirbornePositionBaro::decode(data)?),
9..=18 => ADSBMessage::AirbornePosition(AirbornePosition::decode(type_code, data)?),
19 => ADSBMessage::AirborneVelocities(AirborneVelocities::decode(data)?),
20..=22 => ADSBMessage::AirbornePositionGNSS(AirbornePositionGNSS::decode(data)?),
20..=22 => ADSBMessage::AirbornePosition(AirbornePosition::decode(type_code, data)?),
23..=27 => ADSBMessage::Reserved(type_code),
28 => ADSBMessage::AircraftStatus(AircraftStatus::decode(data)?),
29 => ADSBMessage::TargetState(TargetState::decode(data)?),
@@ -199,7 +198,7 @@ impl ADSBMessage {
return Err(Error::new(
ErrorKind::InvalidData,
format!("unsupported ADS-B type_code {}", type_code),
))
));
}
};
@@ -310,10 +309,10 @@ impl SurfacePosition {
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AirbornePositionBaro {}
pub struct AirbornePosition {}
impl AirbornePositionBaro {
pub fn decode(_data: &[u8]) -> Result<Self> {
impl AirbornePosition {
pub fn decode(_type_code: u8, _data: &[u8]) -> Result<Self> {
Ok(Self {})
}
}
@@ -327,15 +326,6 @@ impl AirborneVelocities {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AirbornePositionGNSS {}
impl AirbornePositionGNSS {
pub fn decode(_data: &[u8]) -> Result<Self> {
Ok(Self {})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AircraftStatus {}

View File

@@ -1,6 +1,6 @@
use std::io::{Error, ErrorKind, Result};
pub mod adsb;
pub mod adsb_frame;
pub mod device;
pub fn hex_to_bytes(s: &str) -> Result<Vec<u8>> {
@@ -20,7 +20,7 @@ pub fn hex_to_bytes(s: &str) -> Result<Vec<u8>> {
return Err(Error::new(
ErrorKind::InvalidInput,
format!("invalid hex char '{}'", chunk[0] as char),
))
));
}
};
let lo = match hex_val(chunk[1]) {
@@ -29,7 +29,7 @@ pub fn hex_to_bytes(s: &str) -> Result<Vec<u8>> {
return Err(Error::new(
ErrorKind::InvalidInput,
format!("invalid hex char '{}'", chunk[1] as char),
))
));
}
};
out.push((hi << 4) | lo);

View File

@@ -1,52 +0,0 @@
mod rusb_device;
mod tcp_device;
use crate::rusb_device::RusbDevice;
use crate::tcp_device::TcpDevice;
use adsb_lib::adsb::ADSBFrame;
use adsb_lib::{hex_to_bytes, device::run};
use clap::Parser;
use std::io::Result;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct ReceiverArgs {
#[arg(long)]
decode: Option<String>,
#[arg(long)]
net: bool,
#[arg(long, default_value = "127.0.0.1:9999", requires = "net")]
addr: String,
#[arg(long)]
usb: bool,
}
fn main() -> Result<()> {
let args = ReceiverArgs::parse();
if let Some(mut hex_string) = args.decode {
if let Some(stripped) = hex_string.strip_prefix("0x") {
hex_string = stripped.to_string();
}
let buf = hex_to_bytes(&hex_string)?;
let frame = ADSBFrame::decode(&buf)?;
println!("{}", frame);
return Ok(());
}
if args.net {
println!("Connecting to network {}", args.addr);
let mut device = TcpDevice::connect(&args.addr)?;
device.run()
} else if args.usb {
println!("Connecting to device");
let mut device = RusbDevice::open()?;
run(&mut device)
} else {
println!("No connection specified");
Ok(())
}
}

View File

@@ -1,8 +0,0 @@
[package]
name = "adsb_sim"
version = "0.1.0"
edition = "2024"
[dependencies]
adsb_lib = { path = "../adsb_lib" }
clap = { version = "4.5.37", features = ["derive"] }

View File

@@ -1,9 +1,11 @@
[package]
name = "adsb_recv"
name = "squawk"
version = "0.1.0"
edition = "2024"
[dependencies]
adsb_lib = { path = "../adsb_lib" }
rusb = "0.9.4"
clap = { version = "4.5.37", features = ["derive"] }
clap = { version = "4.5.37", features = ["derive"] }
log = "0.4.27"
env_logger = "0.11.8"

79
adsb/squawk/src/main.rs Normal file
View File

@@ -0,0 +1,79 @@
mod rusb_device;
mod tcp_device;
use crate::rusb_device::RusbDevice;
use crate::tcp_device::TcpDevice;
use adsb_lib::adsb_frame::ADSBFrame;
use adsb_lib::{hex_to_bytes, device::run};
use clap::Parser;
use std::io::Result;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = "An ADS-B Receiver")]
struct ReceiverArgs {
/// Hex-string to decode
#[arg(long)]
decode: Option<String>,
/// Connect to the network
#[arg(long)]
net: bool,
/// Network listen address (requires --net)
#[arg(long, requires = "net", hide = true)]
addr: Option<String>,
/// Network listen port (requires --net)
#[arg(long, requires = "net", hide = true)]
port: Option<u16>,
/// Connect to the USB device
#[arg(long)]
usb: bool,
/// Enable debug logging
#[arg(short, long, action)]
debug: bool,
}
fn main() -> Result<()> {
let args = ReceiverArgs::parse();
let default_filter = if args.debug {
"warn,squawk=debug"
} else {
"warn,squawk=info"
};
env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", default_filter));
// Handle decode mode
if let Some(mut hex_string) = args.decode {
if let Some(stripped) = hex_string.strip_prefix("0x") {
hex_string = stripped.to_string();
}
let buf = hex_to_bytes(&hex_string)?;
let frame = ADSBFrame::decode(&buf)?;
log::info!("{}", frame);
return Ok(());
}
// Handle net mode
if args.net {
let host = args.addr.unwrap_or_else(|| "127.0.0.1".into());
let port = args.port.unwrap_or(9999);
let addr = format!("{host}:{port}");
log::info!("Connecting to network {}", addr);
let mut device = TcpDevice::connect(&addr)?;
device.run()
}
// Handle usb mode
else if args.usb {
log::info!("Connecting to device");
let mut device = RusbDevice::open()?;
run(&mut device)
} else {
log::warn!("No connection specified");
Ok(())
}
}

View File

@@ -1,7 +1,7 @@
use adsb_lib::device::Device;
use std::io::{Error, ErrorKind, Read, Result, Write};
use std::net::TcpStream;
use adsb_lib::adsb::ADSBFrame;
use adsb_lib::adsb_frame::ADSBFrame;
// Tags for framing requests/responses over the TCP socket
const TAG_CTRL_OUT: u8 = 0x10;
@@ -34,7 +34,7 @@ impl TcpDevice {
let mut status = [0u8; 1];
self.socket.read_exact(&mut status)?;
if status[0] != 0 {
eprintln!("Remote reported error status {}", status[0]);
log::error!("Remote reported error status {}", status[0]);
break;
}
@@ -54,7 +54,7 @@ impl TcpDevice {
}
let frame = ADSBFrame::decode(&adsb)?;
println!("{}", frame);
log::info!("{}", frame);
}
Ok(())

View File

@@ -0,0 +1,10 @@
[package]
name = "squawk_sim"
version = "0.1.0"
edition = "2024"
[dependencies]
adsb_lib = { path = "../adsb_lib" }
clap = { version = "4.5.37", features = ["derive"] }
log = "0.4.27"
env_logger = "0.11.8"

View File

@@ -26,11 +26,14 @@ struct SimulationArgs {
}
fn main() {
env_logger::init_from_env(
env_logger::Env::default().filter_or("RUST_LOG", "warn,squawk_sim=info"),
);
let args = SimulationArgs::parse();
// Build the bind address, e.g. "127.0.0.1:9999"
let bind_address = format!("{}:{}", args.host, args.port);
println!("Listening on {}", bind_address);
log::info!("Listening on {}", bind_address);
// Start listening for incoming TCP connections
let listener = TcpListener::bind(&bind_address)
@@ -43,18 +46,18 @@ fn main() {
// Spawn a thread per client
thread::spawn(move || {
if let Err(err) = handle_client_connection(client_stream) {
eprintln!("connection error: {}", err);
log::error!("connection error: {}", err);
}
});
}
Err(err) => eprintln!("error accepting connection: {}", err),
Err(err) => log::error!("error accepting connection: {}", err),
}
}
}
/// Handle a single client connection
fn handle_client_connection(mut connection: TcpStream) -> Result<()> {
println!("Connection established");
log::info!("Connection established");
loop {
// Read the 4-byte header: [tag:1][bRequest:1][length:2 LE]
let mut header_buffer = [0u8; 4];
@@ -67,13 +70,17 @@ fn handle_client_connection(mut connection: TcpStream) -> Result<()> {
let _b_request = header_buffer[1];
let payload_length = u16::from_le_bytes([header_buffer[2], header_buffer[3]]) as usize;
// println!("Received message '{:02x}' with payload length {}", message_tag, payload_length);
log::trace!(
"Received message '{:02x}' with payload length {}",
message_tag,
payload_length
);
// Read the optional payload
// let mut payload_buffer = vec![0u8; payload_length];
// if payload_length > 0 {
// if connection.read(&mut payload_buffer).is_err() {
// eprintln!("error reading payload buffer");
// log::error!("error reading payload buffer");
// break;
// }
// }
@@ -81,19 +88,19 @@ fn handle_client_connection(mut connection: TcpStream) -> Result<()> {
// Dispatch based on the framing tag
match message_tag {
TAG_CONTROL_OUT => {
// println!("Received control out");
log::trace!("Received control out");
// Acknowledge with a status OK
connection.write_all(&[0u8])?;
}
TAG_CONTROL_IN => {
// println!("Received control in");
log::trace!("Received control in");
// STATUS(1) + LENGTH(2) + dummy payload
connection.write_all(&[0x00])?;
connection.write_all(&(payload_length as u16).to_le_bytes())?;
connection.write_all(&vec![0x42; payload_length])?;
}
TAG_BULK => {
// println!("Received bulk message");
log::trace!("Received bulk message");
let iq = generate_adsb_iq();
// STATUS(1) + LENGTH(4) + IQ data
connection.write_all(&[0x00])?;
@@ -104,13 +111,13 @@ fn handle_client_connection(mut connection: TcpStream) -> Result<()> {
thread::sleep(Duration::from_millis(10));
}
_unknown_tag => {
eprintln!("Unknown message tag {}", _unknown_tag);
log::warn!("Unknown message tag {}", _unknown_tag);
break;
}
}
}
println!("Connection closed");
log::info!("Connection closed");
Ok(())
}

View File

@@ -11,5 +11,5 @@ post {
}
body:multipart-form {
: @file(/Users/bsherriff/git/private/aviation-weather/data/airports_2023-12-21.json)
: @file(/Users/bsherriff/git/private/aviation/data/airports_2023-12-21.json)
}