Updated adsb stuff
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"adsb_lib",
|
"adsb_lib",
|
||||||
"adsb_recv",
|
"squawk",
|
||||||
"adsb_sim"
|
"squawk_sim"
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
package.version = "0.1.0"
|
package.version = "0.1.0"
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ impl TryFrom<u8> for Capability {
|
|||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
ErrorKind::InvalidData,
|
ErrorKind::InvalidData,
|
||||||
format!("invalid CA value: {}", value),
|
format!("invalid CA value: {}", value),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(capability)
|
Ok(capability)
|
||||||
@@ -164,9 +164,8 @@ impl TryFrom<u8> for Capability {
|
|||||||
pub enum ADSBMessage {
|
pub enum ADSBMessage {
|
||||||
AircraftIdentification(AircraftIdentification),
|
AircraftIdentification(AircraftIdentification),
|
||||||
SurfacePosition(SurfacePosition),
|
SurfacePosition(SurfacePosition),
|
||||||
AirbornePositionBaro(AirbornePositionBaro),
|
AirbornePosition(AirbornePosition),
|
||||||
AirborneVelocities(AirborneVelocities),
|
AirborneVelocities(AirborneVelocities),
|
||||||
AirbornePositionGNSS(AirbornePositionGNSS),
|
|
||||||
Reserved(u8),
|
Reserved(u8),
|
||||||
AircraftStatus(AircraftStatus),
|
AircraftStatus(AircraftStatus),
|
||||||
TargetState(TargetState),
|
TargetState(TargetState),
|
||||||
@@ -188,9 +187,9 @@ impl ADSBMessage {
|
|||||||
ADSBMessage::AircraftIdentification(AircraftIdentification::decode(type_code, data)?)
|
ADSBMessage::AircraftIdentification(AircraftIdentification::decode(type_code, data)?)
|
||||||
}
|
}
|
||||||
5..=8 => ADSBMessage::SurfacePosition(SurfacePosition::decode(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)?),
|
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),
|
23..=27 => ADSBMessage::Reserved(type_code),
|
||||||
28 => ADSBMessage::AircraftStatus(AircraftStatus::decode(data)?),
|
28 => ADSBMessage::AircraftStatus(AircraftStatus::decode(data)?),
|
||||||
29 => ADSBMessage::TargetState(TargetState::decode(data)?),
|
29 => ADSBMessage::TargetState(TargetState::decode(data)?),
|
||||||
@@ -199,7 +198,7 @@ impl ADSBMessage {
|
|||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
ErrorKind::InvalidData,
|
ErrorKind::InvalidData,
|
||||||
format!("unsupported ADS-B type_code {}", type_code),
|
format!("unsupported ADS-B type_code {}", type_code),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -310,10 +309,10 @@ impl SurfacePosition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct AirbornePositionBaro {}
|
pub struct AirbornePosition {}
|
||||||
|
|
||||||
impl AirbornePositionBaro {
|
impl AirbornePosition {
|
||||||
pub fn decode(_data: &[u8]) -> Result<Self> {
|
pub fn decode(_type_code: u8, _data: &[u8]) -> Result<Self> {
|
||||||
Ok(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)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct AircraftStatus {}
|
pub struct AircraftStatus {}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::io::{Error, ErrorKind, Result};
|
use std::io::{Error, ErrorKind, Result};
|
||||||
|
|
||||||
pub mod adsb;
|
pub mod adsb_frame;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
|
|
||||||
pub fn hex_to_bytes(s: &str) -> Result<Vec<u8>> {
|
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(
|
return Err(Error::new(
|
||||||
ErrorKind::InvalidInput,
|
ErrorKind::InvalidInput,
|
||||||
format!("invalid hex char '{}'", chunk[0] as char),
|
format!("invalid hex char '{}'", chunk[0] as char),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let lo = match hex_val(chunk[1]) {
|
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(
|
return Err(Error::new(
|
||||||
ErrorKind::InvalidInput,
|
ErrorKind::InvalidInput,
|
||||||
format!("invalid hex char '{}'", chunk[1] as char),
|
format!("invalid hex char '{}'", chunk[1] as char),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
out.push((hi << 4) | lo);
|
out.push((hi << 4) | lo);
|
||||||
|
|||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"] }
|
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "adsb_recv"
|
name = "squawk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
adsb_lib = { path = "../adsb_lib" }
|
adsb_lib = { path = "../adsb_lib" }
|
||||||
rusb = "0.9.4"
|
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
79
adsb/squawk/src/main.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use adsb_lib::device::Device;
|
use adsb_lib::device::Device;
|
||||||
use std::io::{Error, ErrorKind, Read, Result, Write};
|
use std::io::{Error, ErrorKind, Read, Result, Write};
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use adsb_lib::adsb::ADSBFrame;
|
use adsb_lib::adsb_frame::ADSBFrame;
|
||||||
|
|
||||||
// Tags for framing requests/responses over the TCP socket
|
// Tags for framing requests/responses over the TCP socket
|
||||||
const TAG_CTRL_OUT: u8 = 0x10;
|
const TAG_CTRL_OUT: u8 = 0x10;
|
||||||
@@ -34,7 +34,7 @@ impl TcpDevice {
|
|||||||
let mut status = [0u8; 1];
|
let mut status = [0u8; 1];
|
||||||
self.socket.read_exact(&mut status)?;
|
self.socket.read_exact(&mut status)?;
|
||||||
if status[0] != 0 {
|
if status[0] != 0 {
|
||||||
eprintln!("Remote reported error status {}", status[0]);
|
log::error!("Remote reported error status {}", status[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ impl TcpDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let frame = ADSBFrame::decode(&adsb)?;
|
let frame = ADSBFrame::decode(&adsb)?;
|
||||||
println!("{}", frame);
|
log::info!("{}", frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
10
adsb/squawk_sim/Cargo.toml
Normal file
10
adsb/squawk_sim/Cargo.toml
Normal 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"
|
||||||
@@ -26,11 +26,14 @@ struct SimulationArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
env_logger::init_from_env(
|
||||||
|
env_logger::Env::default().filter_or("RUST_LOG", "warn,squawk_sim=info"),
|
||||||
|
);
|
||||||
let args = SimulationArgs::parse();
|
let args = SimulationArgs::parse();
|
||||||
|
|
||||||
// Build the bind address, e.g. "127.0.0.1:9999"
|
// Build the bind address, e.g. "127.0.0.1:9999"
|
||||||
let bind_address = format!("{}:{}", args.host, args.port);
|
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
|
// Start listening for incoming TCP connections
|
||||||
let listener = TcpListener::bind(&bind_address)
|
let listener = TcpListener::bind(&bind_address)
|
||||||
@@ -43,18 +46,18 @@ fn main() {
|
|||||||
// Spawn a thread per client
|
// Spawn a thread per client
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
if let Err(err) = handle_client_connection(client_stream) {
|
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
|
/// Handle a single client connection
|
||||||
fn handle_client_connection(mut connection: TcpStream) -> Result<()> {
|
fn handle_client_connection(mut connection: TcpStream) -> Result<()> {
|
||||||
println!("Connection established");
|
log::info!("Connection established");
|
||||||
loop {
|
loop {
|
||||||
// Read the 4-byte header: [tag:1][bRequest:1][length:2 LE]
|
// Read the 4-byte header: [tag:1][bRequest:1][length:2 LE]
|
||||||
let mut header_buffer = [0u8; 4];
|
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 _b_request = header_buffer[1];
|
||||||
let payload_length = u16::from_le_bytes([header_buffer[2], header_buffer[3]]) as usize;
|
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
|
// Read the optional payload
|
||||||
// let mut payload_buffer = vec![0u8; payload_length];
|
// let mut payload_buffer = vec![0u8; payload_length];
|
||||||
// if payload_length > 0 {
|
// if payload_length > 0 {
|
||||||
// if connection.read(&mut payload_buffer).is_err() {
|
// if connection.read(&mut payload_buffer).is_err() {
|
||||||
// eprintln!("error reading payload buffer");
|
// log::error!("error reading payload buffer");
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
@@ -81,19 +88,19 @@ fn handle_client_connection(mut connection: TcpStream) -> Result<()> {
|
|||||||
// Dispatch based on the framing tag
|
// Dispatch based on the framing tag
|
||||||
match message_tag {
|
match message_tag {
|
||||||
TAG_CONTROL_OUT => {
|
TAG_CONTROL_OUT => {
|
||||||
// println!("Received control out");
|
log::trace!("Received control out");
|
||||||
// Acknowledge with a status OK
|
// Acknowledge with a status OK
|
||||||
connection.write_all(&[0u8])?;
|
connection.write_all(&[0u8])?;
|
||||||
}
|
}
|
||||||
TAG_CONTROL_IN => {
|
TAG_CONTROL_IN => {
|
||||||
// println!("Received control in");
|
log::trace!("Received control in");
|
||||||
// STATUS(1) + LENGTH(2) + dummy payload
|
// STATUS(1) + LENGTH(2) + dummy payload
|
||||||
connection.write_all(&[0x00])?;
|
connection.write_all(&[0x00])?;
|
||||||
connection.write_all(&(payload_length as u16).to_le_bytes())?;
|
connection.write_all(&(payload_length as u16).to_le_bytes())?;
|
||||||
connection.write_all(&vec![0x42; payload_length])?;
|
connection.write_all(&vec![0x42; payload_length])?;
|
||||||
}
|
}
|
||||||
TAG_BULK => {
|
TAG_BULK => {
|
||||||
// println!("Received bulk message");
|
log::trace!("Received bulk message");
|
||||||
let iq = generate_adsb_iq();
|
let iq = generate_adsb_iq();
|
||||||
// STATUS(1) + LENGTH(4) + IQ data
|
// STATUS(1) + LENGTH(4) + IQ data
|
||||||
connection.write_all(&[0x00])?;
|
connection.write_all(&[0x00])?;
|
||||||
@@ -104,13 +111,13 @@ fn handle_client_connection(mut connection: TcpStream) -> Result<()> {
|
|||||||
thread::sleep(Duration::from_millis(10));
|
thread::sleep(Duration::from_millis(10));
|
||||||
}
|
}
|
||||||
_unknown_tag => {
|
_unknown_tag => {
|
||||||
eprintln!("Unknown message tag {}", _unknown_tag);
|
log::warn!("Unknown message tag {}", _unknown_tag);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Connection closed");
|
log::info!("Connection closed");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,5 +11,5 @@ post {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body:multipart-form {
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user