Temp got sim to work with tcp device by stripping out a lot of the logic.
This commit is contained in:
@@ -109,18 +109,18 @@ impl Display for ADSBFrame {
|
||||
}
|
||||
}
|
||||
|
||||
/// Transponder Capability (CA) codes from the ADS‑B spec
|
||||
/// Transponder Capability (CA) codes from the ADS-B spec
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Capability {
|
||||
/// 0: Level 1 transponder
|
||||
Level1,
|
||||
/// 1–3: Reserved
|
||||
/// 1-3: Reserved
|
||||
Reserved(u8),
|
||||
/// 4: Level 2+ transponder, on‑ground (can set CA=7)
|
||||
/// 4: Level 2+ transponder, ground (can set CA=7)
|
||||
Level2OnGround,
|
||||
/// 5: Level 2+ transponder, airborne (can set CA=7)
|
||||
Level2Airborne,
|
||||
/// 6: Level 2+ transponder, either on‑ground or airborne (can set CA=7)
|
||||
/// 6: Level 2+ transponder, either ground or airborne (can set CA=7)
|
||||
Level2Either,
|
||||
/// 7: Downlink Request = 0, or Flight Status = 2,3,4,5
|
||||
DownlinkRequestOrFlightStatus,
|
||||
@@ -198,7 +198,7 @@ impl ADSBMessage {
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
format!("unsupported ADS‑B type_code {}", type_code),
|
||||
format!("unsupported ADS-B type_code {}", type_code),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
110
adsb/adsb_lib/src/device.rs
Normal file
110
adsb/adsb_lib/src/device.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
pub trait Device {
|
||||
/// Send a control message to the device
|
||||
fn control_send(&mut self, b_request: u8, data: &[u8]) -> std::io::Result<()>;
|
||||
/// Receive a control message from a device
|
||||
fn control_recv(&mut self, b_request: u8, length: usize) -> std::io::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]) -> std::io::Result<usize>;
|
||||
}
|
||||
|
||||
pub fn run<S: Device>(device: &mut S) -> std::io::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!();
|
||||
}
|
||||
}
|
||||
@@ -1,117 +1,7 @@
|
||||
use std::io::{Error, ErrorKind, Result};
|
||||
|
||||
pub mod adsb;
|
||||
|
||||
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!();
|
||||
}
|
||||
}
|
||||
pub mod device;
|
||||
|
||||
pub fn hex_to_bytes(s: &str) -> Result<Vec<u8>> {
|
||||
let bytes = s.as_bytes();
|
||||
|
||||
Reference in New Issue
Block a user