Compare commits
5 Commits
00a90d56dc
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 90ba8420c5 | |||
| 0d932efc83 | |||
| 7c9e033015 | |||
| 66eeceb728 | |||
| 8337ed478d |
@@ -1,2 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
/out
|
/out
|
||||||
|
/riglib
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# ASMR
|
||||||
|
ASMR: Automatic S-Meter Reader
|
||||||
|
|
||||||
|
This program reads location from a GPS dongle and the S-Meter from a
|
||||||
|
transceiver via a serial port and stores the results in a CSV file
|
||||||
|
so you can run analysis in another program.
|
||||||
|
|
||||||
|
Inspired by RFI Mapper (RFIM) by [W4DD](https://www.qrz.com/db/W4DD)
|
||||||
|
and written in Rust.
|
||||||
|
|
||||||
|
# Use Cases
|
||||||
|
- Drive a route and measure variation in noise level, to determine local noise sources
|
||||||
|
- Record noise level at a fixed location over time, to determine temporal noise patterns
|
||||||
|
- Some combination of the two
|
||||||
|
|
||||||
|
# Help
|
||||||
|
```
|
||||||
|
asmr --help
|
||||||
|
|
||||||
|
ASMR: Automatic S-Meter Reader
|
||||||
|
|
||||||
|
Usage: asmr [OPTIONS]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-r, --rig <RIG> Output file path [default: qmx]
|
||||||
|
-c, --com <COM> Rig COM port
|
||||||
|
-g, --gps <GPS> GPS COM port
|
||||||
|
-o, --file <FILE> Output file path
|
||||||
|
-f, --freq <FREQ> Frequency
|
||||||
|
-w, --wait <WAIT> Seconds to wait between measurements [default: 5]
|
||||||
|
-h, --help Print help
|
||||||
|
-V, --version Print version
|
||||||
|
```
|
||||||
|
|
||||||
|
# Contact
|
||||||
|
- [@W1CDN@mastodon.radio](https://mastodon.radio/@W1CDN)
|
||||||
|
- admin@w1cdn.net
|
||||||
+52
-66
@@ -115,10 +115,20 @@ struct Rig {
|
|||||||
data_bits: DataBits,
|
data_bits: DataBits,
|
||||||
stop_bits: StopBits,
|
stop_bits: StopBits,
|
||||||
parity: Parity,
|
parity: Parity,
|
||||||
|
s_meter_cat: String,
|
||||||
|
freq_cat: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a rig struct
|
// Create a rig struct
|
||||||
fn build_rig(name: &str, baud_rate: u32, data_bits: u8, stop_bits: u8, parity: &str) -> Rig {
|
fn build_rig(
|
||||||
|
name: &str,
|
||||||
|
baud_rate: u32,
|
||||||
|
data_bits: u8,
|
||||||
|
stop_bits: u8,
|
||||||
|
parity: &str,
|
||||||
|
s_meter_cat: &str,
|
||||||
|
freq_cat: &str,
|
||||||
|
) -> Rig {
|
||||||
Rig {
|
Rig {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
baud_rate,
|
baud_rate,
|
||||||
@@ -127,19 +137,21 @@ fn build_rig(name: &str, baud_rate: u32, data_bits: u8, stop_bits: u8, parity: &
|
|||||||
6 => DataBits::Six,
|
6 => DataBits::Six,
|
||||||
7 => DataBits::Seven,
|
7 => DataBits::Seven,
|
||||||
8 => DataBits::Eight,
|
8 => DataBits::Eight,
|
||||||
_ => DataBits::Eight
|
_ => DataBits::Eight,
|
||||||
},
|
},
|
||||||
stop_bits: match stop_bits {
|
stop_bits: match stop_bits {
|
||||||
1 => StopBits::One,
|
1 => StopBits::One,
|
||||||
2 => StopBits::Two,
|
2 => StopBits::Two,
|
||||||
_ => StopBits::One
|
_ => StopBits::One,
|
||||||
},
|
},
|
||||||
parity: match parity {
|
parity: match parity {
|
||||||
"none" => Parity::None,
|
"none" => Parity::None,
|
||||||
"odd" => Parity::Odd,
|
"odd" => Parity::Odd,
|
||||||
"even" => Parity::Even,
|
"even" => Parity::Even,
|
||||||
_ => Parity::None,
|
_ => Parity::None,
|
||||||
}
|
},
|
||||||
|
s_meter_cat: s_meter_cat.to_string(),
|
||||||
|
freq_cat: freq_cat.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,19 +159,18 @@ fn build_rig(name: &str, baud_rate: u32, data_bits: u8, stop_bits: u8, parity: &
|
|||||||
// https://kevinlynagh.com/notes/match-vs-lookup/
|
// https://kevinlynagh.com/notes/match-vs-lookup/
|
||||||
fn get_rig(x: &str) -> Rig {
|
fn get_rig(x: &str) -> Rig {
|
||||||
match x {
|
match x {
|
||||||
"qmx" => build_rig("qmx", 4800, 8, 2, "none"),
|
"qmx" => build_rig("qmx", 9600, 8, 2, "none", "SM", "FA"),
|
||||||
"ic-7300" => build_rig("ic-7300", 115200, 8, 1, "none"),
|
//"ic-7300" => build_rig("ic-7300", 115200, 8, 1, "none", "1502"),
|
||||||
_ => {
|
_ => {
|
||||||
// This prints a message every loop but that's OK.
|
// This prints a message every loop but that's OK.
|
||||||
println!("Rig '{x}' in rig list. Using default connection values.");
|
println!("Rig '{x}' in rig list. Using default connection values.");
|
||||||
build_rig("qmx", 4800, 8, 2, "none")
|
build_rig("qmx", 9600, 8, 2, "none", "SM", "FA")
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read S-meter
|
// Read S-meter
|
||||||
fn get_smeter(comport: &str, rig_name: &str) -> String {
|
fn get_smeter(comport: &str, rig_name: &str, frequency: u32) -> i32 {
|
||||||
|
|
||||||
// Get the serial connection info for the rig name
|
// Get the serial connection info for the rig name
|
||||||
let rig = get_rig(rig_name);
|
let rig = get_rig(rig_name);
|
||||||
|
|
||||||
@@ -172,10 +183,21 @@ fn get_smeter(comport: &str, rig_name: &str) -> String {
|
|||||||
.open()
|
.open()
|
||||||
.expect("Failed to open port");
|
.expect("Failed to open port");
|
||||||
|
|
||||||
|
// Set the requested frequency
|
||||||
|
let output = format!("{}{};", rig.freq_cat, frequency);
|
||||||
|
|
||||||
|
match port.write(output.as_bytes()) {
|
||||||
|
Ok(_) => {
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
}
|
||||||
|
Err(ref e) if e.kind() == ErrorKind::TimedOut => (),
|
||||||
|
Err(e) => eprintln!("{:?}", e),
|
||||||
|
}
|
||||||
|
|
||||||
// Duh, you need the ";" on the end!
|
// Duh, you need the ";" on the end!
|
||||||
// let output = "FA14075000;"; // set VFO A frequency
|
// let output = "FA14075000;"; // set VFO A frequency
|
||||||
// let output = "FA;"; // ask for VFO A frequency
|
// let output = "FA;"; // ask for VFO A frequency
|
||||||
let output = "SM;"; // ask for S-meter reading
|
let output = format!("{};", rig.s_meter_cat); //"SM;"; // ask for S-meter reading
|
||||||
// What are we actually sending?
|
// What are we actually sending?
|
||||||
//dbg!(output.as_bytes());
|
//dbg!(output.as_bytes());
|
||||||
|
|
||||||
@@ -200,7 +222,13 @@ fn get_smeter(comport: &str, rig_name: &str) -> String {
|
|||||||
//let value = data;
|
//let value = data;
|
||||||
// For S-meter, just take the numbers
|
// For S-meter, just take the numbers
|
||||||
let value = &data[2..5];
|
let value = &data[2..5];
|
||||||
return format!("{}", value);
|
let value_i = value.parse::<i32>().unwrap();
|
||||||
|
// return format!("{}", value);
|
||||||
|
if rig_name == "qmx" {
|
||||||
|
return (value_i as f32 / 6.0) as i32;
|
||||||
|
} else {
|
||||||
|
return value_i;
|
||||||
|
}
|
||||||
// return;
|
// return;
|
||||||
}
|
}
|
||||||
Err(_) => {} // lol that I can just not put a return in?
|
Err(_) => {} // lol that I can just not put a return in?
|
||||||
@@ -208,40 +236,6 @@ fn get_smeter(comport: &str, rig_name: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set frequency
|
|
||||||
fn set_freq(comport: &str, freq: u32) -> String {
|
|
||||||
let mut port = serialport::new(comport, 4800)
|
|
||||||
.data_bits(DataBits::Eight)
|
|
||||||
.stop_bits(StopBits::Two)
|
|
||||||
.parity(Parity::None)
|
|
||||||
.timeout(Duration::from_millis(100))
|
|
||||||
.open()
|
|
||||||
.expect("Failed to open port");
|
|
||||||
|
|
||||||
// Duh, you need the ";" on the end!
|
|
||||||
//let output = "FA14075000;"; // set VFO A frequency
|
|
||||||
let output = format!("FA{};", freq);
|
|
||||||
//println!("{output}");
|
|
||||||
|
|
||||||
match port.write(output.as_bytes()) {
|
|
||||||
Ok(_) => {
|
|
||||||
std::io::stdout().flush().unwrap();
|
|
||||||
}
|
|
||||||
Err(ref e) if e.kind() == ErrorKind::TimedOut => (),
|
|
||||||
Err(e) => eprintln!("{:?}", e),
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut buf = [0u8; 1024];
|
|
||||||
match port.read(&mut buf) {
|
|
||||||
Ok(_) => {
|
|
||||||
return format!("Frequency set.");
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
return format!("Failed to set frequency.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write row to a file
|
// Write row to a file
|
||||||
fn write_row(str_arr: [String; 5], file: &String, fmt: &str) -> Result<(), Box<dyn Error>> {
|
fn write_row(str_arr: [String; 5], file: &String, fmt: &str) -> Result<(), Box<dyn Error>> {
|
||||||
// From https://docs.rs/csv/latest/csv/tutorial/index.html#writing-csv
|
// From https://docs.rs/csv/latest/csv/tutorial/index.html#writing-csv
|
||||||
@@ -339,31 +333,23 @@ fn main() {
|
|||||||
} //todo!()
|
} //todo!()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the requested frequency
|
|
||||||
set_freq(&com, frequency);
|
|
||||||
|
|
||||||
println!("Press Ctrl + C to quit");
|
println!("Press Ctrl + C to quit");
|
||||||
|
|
||||||
// Simple test loop to make sure we are getting values each time
|
|
||||||
//for _i in 1..11 {
|
|
||||||
loop {
|
loop {
|
||||||
// Get location
|
// Get location
|
||||||
let ll = get_loc(gps.clone());
|
let ll = get_loc(gps.clone());
|
||||||
// Get datestamp
|
// Get datestamp
|
||||||
let date = Local::now();
|
let date = Local::now();
|
||||||
// Get S-meter
|
// Get S-meter
|
||||||
let s_val = get_smeter(&com, &rig);
|
let s_val = get_smeter(&com, &rig, frequency);
|
||||||
//println!("{a}");
|
// Print measurements and simple graph
|
||||||
match s_val.parse::<i32>() {
|
println!(
|
||||||
// Simple graph as we go. Eventually this will be replaced.
|
"{} {:#03} {}",
|
||||||
Ok(n) => println!(
|
date.format("%Y-%m-%d %H:%M:%S").to_string(),
|
||||||
"{} {} {}",
|
s_val,
|
||||||
date.format("%Y-%m-%d %H:%M:%S").to_string(),
|
"#".repeat(s_val.try_into().unwrap())
|
||||||
s_val,
|
);
|
||||||
"#".repeat(n.try_into().unwrap())
|
|
||||||
),
|
|
||||||
Err(_e) => todo!(),
|
|
||||||
}
|
|
||||||
// If they provided a file name
|
// If they provided a file name
|
||||||
if file_out != "no file" {
|
if file_out != "no file" {
|
||||||
if let Err(err) = write_row(
|
if let Err(err) = write_row(
|
||||||
@@ -373,7 +359,7 @@ fn main() {
|
|||||||
format!("{:09}", frequency),
|
format!("{:09}", frequency),
|
||||||
format!("{:.8}", ll[0]),
|
format!("{:.8}", ll[0]),
|
||||||
format!("{:.8}", ll[1]),
|
format!("{:.8}", ll[1]),
|
||||||
s_val.to_string(),
|
format!("{}", s_val),
|
||||||
],
|
],
|
||||||
&file_out,
|
&file_out,
|
||||||
"csv",
|
"csv",
|
||||||
|
|||||||
Reference in New Issue
Block a user