Adding base for adsb
This commit is contained in:
4
adsb/adsb_lib/Cargo.toml
Normal file
4
adsb/adsb_lib/Cargo.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "adsb_lib"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
119
adsb/adsb_lib/src/lib.rs
Normal file
119
adsb/adsb_lib/src/lib.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use std::io::Result;
|
||||
|
||||
pub trait RtlDevice {
|
||||
/// Send a control message to the device
|
||||
fn control_send(&mut self, b_request: u8, data: &[u8]) -> Result<()>;
|
||||
/// Receive a control message from a device
|
||||
fn control_recv(&mut self, b_request: u8, length: usize) -> Result<Vec<u8>>;
|
||||
/// Read a chunk of raw IQ samples from the bulk-in endpoint
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `buffer` - the slice to fill with received data
|
||||
///
|
||||
/// # Returns
|
||||
/// Number of bytes actually read
|
||||
fn read_bulk(&mut self, buffer: &mut [u8]) -> Result<usize>;
|
||||
}
|
||||
|
||||
pub fn run<S: RtlDevice>(device: &mut S) -> Result<()> {
|
||||
// RESET
|
||||
device.control_send(0x00, &[])?;
|
||||
// SET_FREQ
|
||||
device.control_send(0x02, &1_090_000_000u32.to_le_bytes())?;
|
||||
// SET_SR
|
||||
device.control_send(0x03, &2_400_000u32.to_le_bytes())?;
|
||||
// AGC on
|
||||
device.control_send(0x04, &[1])?;
|
||||
|
||||
// Precompute the preamble pattern in “half‐bit” units (16 samples)
|
||||
let preamble_halfbit_pattern = [
|
||||
1,1, 0,0, 1,1, 0,0,
|
||||
1,1, 0,0, 0,0, 0,0
|
||||
];
|
||||
|
||||
// Create a big buffer to hold raw I/Q bytes
|
||||
let mut iq_buffer = [0u8; 16_384];
|
||||
|
||||
loop {
|
||||
// Read one bulk transfer's worth of I/Q data
|
||||
let bytes_read = device.read_bulk(&mut iq_buffer)?;
|
||||
if bytes_read < 32 {
|
||||
// Must be at least 16 I/Q pairs
|
||||
continue;
|
||||
}
|
||||
|
||||
let raw = &iq_buffer[..bytes_read];
|
||||
|
||||
// Build a vector of "bit-samples" by thresholding I
|
||||
// raw is [I0,Q0,I1,Q1,...], so step by 2
|
||||
let mut halfbit_samples = Vec::with_capacity(raw.len() / 2);
|
||||
for pair in raw.chunks_exact(2) {
|
||||
let i_sample = pair[0] as u16;
|
||||
// Threshold at 200
|
||||
halfbit_samples.push(if i_sample > 200 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
});
|
||||
}
|
||||
|
||||
// Scan for the 16-sample preamble
|
||||
let mut data_start_index = None;
|
||||
for idx in 0..halfbit_samples.len().saturating_sub(16) {
|
||||
if &halfbit_samples[idx..idx + 16] == preamble_halfbit_pattern {
|
||||
data_start_index = Some(idx + 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let data_start = match data_start_index {
|
||||
Some(i) => i,
|
||||
None => continue // No preamble found in this chunk
|
||||
};
|
||||
|
||||
// Collect 112 ADS-B bits, each manchester-encoded into 2 half-bits
|
||||
// 224 half-bit samples total
|
||||
let required_samples = 112 * 2;
|
||||
if data_start + required_samples > halfbit_samples.len() {
|
||||
// Not enough in this buffer
|
||||
continue;
|
||||
}
|
||||
let manchester_slice = &halfbit_samples[data_start..data_start + required_samples];
|
||||
|
||||
// Manchester-decode pairs back into plain bits
|
||||
let mut adsb_bits = Vec::with_capacity(112);
|
||||
for window in manchester_slice.chunks_exact(2) {
|
||||
match window {
|
||||
[1, 0] => adsb_bits.push(0),
|
||||
[0, 1] => adsb_bits.push(1),
|
||||
_ => {
|
||||
// Failed manchester pattern
|
||||
adsb_bits.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if adsb_bits.len() != 112 {
|
||||
// Data is malformed
|
||||
continue;
|
||||
}
|
||||
|
||||
// Pack 112 bits into 14 bytes (MSB first in each byte)
|
||||
let mut adsb_payload = [0u8; 14];
|
||||
for (bit_index, &bit_value) in adsb_bits.iter().enumerate() {
|
||||
let byte_index = bit_index / 8;
|
||||
let bit_in_byte = 7 - (bit_index % 8);
|
||||
if bit_value == 1 {
|
||||
adsb_payload[byte_index] |= 1 << bit_in_byte;
|
||||
}
|
||||
}
|
||||
|
||||
// Print out the 14-byte payload in hex
|
||||
print!("ADS-B payload: ");
|
||||
for byte in &adsb_payload {
|
||||
print!("{:02X} ", byte);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user