Skip to content

Commit 328a4dc

Browse files
authored
Merge pull request #4 from lizard-brain/multi-device
Multi Device Working
2 parents 39504f4 + 1292930 commit 328a4dc

9 files changed

Lines changed: 195 additions & 100 deletions

File tree

config.ini

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@
99
#
1010
[Setup]
1111
#
12-
# IP Address of Headpat Device
13-
device_ip = 192.168.1.157
14-
#
1512
# Port listening for OSC [Default 9001]
16-
port_rx = 9100
1713
#
14+
port_rx = 9001
1815
#
19-
proximity_parameter = /avatar/parameters/proximity_01
16+
# IP Address of Headpat Device
17+
device_ips = 192.168.1.151 192.168.1.157 192.168.1.153
2018
#
21-
max_speed_parameter = /avatar/parameters/max_speed
19+
# Unity Proximity parameter[s]
20+
proximity_parameters_multi = proximity_01 proximity_02 proximity_03
21+
#
22+
max_speed_parameter = max_speed
2223
#
23-
[Haptic_Config]
24+
[Config]
2425
#
2526
# Min Speed of Haptic Motor [5-100]
2627
min_speed = 2
@@ -30,4 +31,7 @@
3031
#
3132
# Max Speed Scalar [10-100]
3233
max_speed_scale = 100
34+
#
35+
# OSC Timeout [seconds]
36+
timeout = 5
3337

giggletech-router/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ authors = ["Giggle Tech <hello@giggletech.io>"
1212

1313
[dependencies]
1414
rosc = "0.4.2"
15-
async-std = "1.12.0"
15+
async-std = { version = "1.8.0", features = ["attributes", "unstable"] }
16+
#async-std = "1.12.0"
1617
log = "0.4.14"
1718
futures-lite = "1.11.3"
1819
thiserror = "1.0.24"
@@ -22,6 +23,9 @@ tokio = { version = "1.13", features = ["full"] }
2223
futures = "0.3"
2324
#ini = "1.3.0"
2425
anyhow = "1.0.44"
26+
once_cell = "1.8.0"
27+
28+
2529

2630

2731

giggletech-router/src/config.rs

Lines changed: 76 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
// config.rs
2+
13
use configparser::ini::Ini;
4+
use std::{net::IpAddr};
25

36
// Banner
47
fn banner_txt(){
@@ -16,61 +19,103 @@ fn banner_txt(){
1619
}
1720

1821
pub(crate) fn load_config() -> (
19-
String, // headpat_device_ip
20-
f32, // min_speed_float
21-
f32, // max_speed_float
22-
f32, // speed_scale_float
23-
String, // port_rx
24-
String, // proximity_parameter_address
25-
String, // max_speed_parameter_address
26-
f32, // Max Speed Low Limit
22+
Vec<String>, // headpat_device_URIs
23+
f32, // min_speed_float
24+
f32, // max_speed_float
25+
f32, // speed_scale_float
26+
String, // port_rx
27+
Vec<String>, // proximity_parameters_multi
28+
String, // max_speed_parameter_address
29+
f32, // Max Speed Low Limit
30+
u64, // Timeout Setting
2731
) {
2832
let mut config = Ini::new();
2933

3034
match config.load("./config.ini") {
3135
Err(why) => panic!("{}", why),
3236
Ok(_) => {}
3337
}
34-
const MAX_SPEED_LOW_LIMIT_CONST: f32 = 0.05;
38+
39+
// Check the format of the IP URIs
40+
let headpat_device_uris: Vec<String> = config.get("Setup", "device_ips")
41+
.unwrap()
42+
.split_whitespace()
43+
.map(|s| s.to_string()) // convert &str to String
44+
.filter_map(|s| {
45+
match s.parse::<IpAddr>() {
46+
Ok(_) => Some(s),
47+
Err(_) => {
48+
println!("Invalid IP address format: {}", s);
49+
None
50+
}
51+
}
52+
})
53+
.collect();
54+
if headpat_device_uris.is_empty() {
55+
eprintln!("Error: no device URIs specified in config file");
56+
// handle error here, e.g. return early from the function or exit the program
57+
}
58+
59+
let proximity_parameters_multi: Vec<String> = config
60+
.get("Setup", "proximity_parameters_multi")
61+
.unwrap()
62+
.split_whitespace()
63+
.map(|s| format!("/avatar/parameters/{}", s))
64+
.collect();
3565

36-
let headpat_device_ip = config.get("Setup", "device_ip").unwrap();
37-
let headpat_device_port = "8888".to_string();
38-
let min_speed = config.get("Haptic_Config", "min_speed").unwrap();
39-
let min_speed_float = min_speed.parse::<f32>().unwrap() / 100.0;
40-
let max_speed = config.get("Haptic_Config", "max_speed").unwrap();
41-
let max_speed_float = max_speed.parse::<f32>().unwrap() / 100.0;
42-
let max_speed_low_limit = MAX_SPEED_LOW_LIMIT_CONST;
43-
let max_speed_float = max_speed_float.max(max_speed_low_limit);
44-
let speed_scale = config.get("Haptic_Config", "max_speed_scale").unwrap();
45-
let speed_scale_float = speed_scale.parse::<f32>().unwrap() / 100.0;
46-
let port_rx = config.get("Setup", "port_rx").unwrap();
66+
67+
if headpat_device_uris.len() != proximity_parameters_multi.len() {
68+
eprintln!("Error: number of device URIs does not match number of proximity parameters");
69+
// handle error here, e.g. return early from the function or exit the program
70+
}
71+
72+
const MAX_SPEED_LOW_LIMIT_CONST: f32 = 0.05;
4773

48-
let proximity_parameter_address = config
49-
.get("Setup", "proximity_parameter")
50-
.unwrap_or_else(|| "/avatar/parameters/proximity_01".into());
51-
let max_speed_parameter_address = config
52-
.get("Setup", "max_speed_parameter")
53-
.unwrap_or_else(|| "/avatar/parameters/max_speed".into());
74+
let min_speed = config.get("Config", "min_speed").unwrap();
75+
let min_speed_float = min_speed.parse::<f32>().unwrap() / 100.0;
76+
77+
let max_speed = config.get("Config", "max_speed").unwrap().parse::<f32>().unwrap() / 100.0;
78+
let max_speed_low_limit = MAX_SPEED_LOW_LIMIT_CONST;
79+
let max_speed_float = max_speed.max(max_speed_low_limit);
80+
81+
let speed_scale = config.get("Config", "max_speed_scale").unwrap();
82+
let speed_scale_float = speed_scale.parse::<f32>().unwrap() / 100.0;
83+
84+
let port_rx = config.get("Setup", "port_rx").unwrap();
85+
86+
let timeout_str = config.get("Config", "timeout").unwrap();
87+
let timeout = timeout_str.parse::<u64>().unwrap_or(0);
88+
89+
let max_speed_parameter_address = format!("/avatar/parameters/{}", config.get("Setup", "max_speed_parameter").unwrap_or_else(|| "/avatar/parameters/max_speed".into()));
5490

5591
println!("\n");
5692
banner_txt();
5793
println!("\n");
58-
println!(" Haptic Device: {}:{}", headpat_device_ip, headpat_device_port);
59-
println!(" Listening for OSC on port: {}", port_rx);
94+
println!(" Device Maps");
95+
for (i, parameter) in proximity_parameters_multi.iter().enumerate() {
96+
println!(" {} => {}", parameter.trim_start_matches("/avatar/parameters/"), headpat_device_uris[i]);
97+
}
98+
99+
println!("\n Listening for OSC on port: {}", port_rx);
60100
println!("\n Vibration Configuration");
61101
println!(" Min Speed: {}%", min_speed);
62102
println!(" Max Speed: {:?}%", max_speed_float * 100.0);
63103
println!(" Scale Factor: {}%", speed_scale);
104+
println!(" Timeout: {}s", timeout);
64105
println!("\nWaiting for pats...");
65106

66107
(
67-
headpat_device_ip,
108+
headpat_device_uris,
68109
min_speed_float,
69110
max_speed_float,
70111
speed_scale_float,
71112
port_rx,
72-
proximity_parameter_address,
113+
proximity_parameters_multi,
73114
max_speed_parameter_address,
74115
max_speed_low_limit,
116+
timeout,
75117
)
76-
}
118+
}
119+
120+
121+

giggletech-router/src/data_processing.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// data_processing.rs
2+
3+
14
pub fn proximity_graph(proximity_signal: f32) -> String {
25
let num_dashes = (proximity_signal * 10.0) as usize;
36
let graph = "-".repeat(num_dashes) + ">";
@@ -19,12 +22,11 @@ pub fn print_speed_limit(headpat_max_rx: f32) {
1922
// Pat Processor
2023
const MOTOR_SPEED_SCALE: f32 = 0.66; // Overvolt Here, OEM config 0.66 going higher than this value will reduce your vibrator motor life
2124

22-
pub fn process_pat(proximity_signal: f32, max_speed: f32, min_speed: f32, speed_scale: f32) -> i32 {
25+
pub fn process_pat(proximity_signal: f32, max_speed: f32, min_speed: f32, speed_scale: f32, proximity_parameter: &String) -> i32 {
2326
let graph_str = proximity_graph(proximity_signal);
2427
let headpat_tx = (((max_speed - min_speed) * proximity_signal + min_speed) * MOTOR_SPEED_SCALE * speed_scale * 255.0).round() as i32;
2528
let proximity_signal = format!("{:.2}", proximity_signal);
26-
let max_speed = format!("{:.2}", max_speed);
27-
eprintln!("Prox: {:5} Motor Tx: {:3} Max Speed: {:5} |{:11}|", proximity_signal, headpat_tx, max_speed, graph_str);
29+
eprintln!("{} Prox: {:5} Motor Tx: {:3} |{:11}|", proximity_parameter.trim_start_matches("/avatar/parameters/") , proximity_signal, headpat_tx, graph_str);
2830

2931
headpat_tx
3032
}

giggletech-router/src/giggletech_osc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// giggletech_osc.rs
2+
13
// GiggleTech OSC Module
24
// Data Sender, Tx & Rx Socket Setup
35

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// handle_proximity_parameter.rs
2+
3+
use async_osc::Result;
4+
use async_std::sync::Arc;
5+
use std::{
6+
sync::atomic::{AtomicBool},
7+
time::Instant,
8+
};
9+
10+
11+
use crate::osc_timeout;
12+
use crate::terminator;
13+
use crate::giggletech_osc;
14+
use crate::data_processing;
15+
16+
17+
pub(crate) async fn handle_proximity_parameter(
18+
running: Arc<AtomicBool>,
19+
device_ip: &Arc<String>,
20+
value: f32,
21+
max_speed: f32,
22+
min_speed: f32,
23+
speed_scale: f32,
24+
proximity_parameters_multi: &String,
25+
) -> Result<()> {
26+
terminator::stop(running.clone()).await?;
27+
28+
// Update Last Signal Time for timeout clock
29+
let mut device_last_signal_times = osc_timeout::DEVICE_LAST_SIGNAL_TIME.lock().unwrap();
30+
device_last_signal_times.insert(device_ip.to_string(), Instant::now());
31+
32+
if value == 0.0 {
33+
println!("Stopping pats...");
34+
terminator::start(running.clone(), &device_ip).await?;
35+
36+
for _ in 0..5 {
37+
giggletech_osc::send_data(&device_ip, 0i32).await?;
38+
}
39+
} else {
40+
giggletech_osc::send_data(&device_ip,
41+
data_processing::process_pat(value, max_speed, min_speed, speed_scale, proximity_parameters_multi)).await?;
42+
43+
}
44+
Ok(())
45+
}

0 commit comments

Comments
 (0)