-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactored gui graphs with data processor
- Loading branch information
1 parent
bd76651
commit 87be269
Showing
6 changed files
with
191 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,137 @@ | ||
use wasm_bindgen::prelude::*; | ||
use serde_cbor::Value; | ||
use serde_wasm_bindgen::to_value; | ||
use serde_wasm_bindgen::{from_value, Serializer}; | ||
use serde::Serialize; | ||
use std::collections::{BTreeMap, BTreeSet}; | ||
use std::collections::{BTreeMap}; | ||
use web_sys::console; | ||
|
||
#[wasm_bindgen] | ||
pub fn process_cbor_data(data: &[u8]) -> JsValue { | ||
match serde_cbor::from_slice::<BTreeMap<String, Value>>(data) { | ||
Ok(decoded_data) => { | ||
let mut data_by_channel: BTreeMap<String, ChannelData> = BTreeMap::new(); | ||
let mut all_features_set: BTreeSet<u32> = BTreeSet::new(); | ||
pub fn process_cbor_data(data: &[u8], channels_js: JsValue) -> JsValue { | ||
// Deserialize channels_js into Vec<String> | ||
let channels: Vec<String> = match from_value(channels_js) { | ||
Ok(c) => c, | ||
Err(err) => { | ||
console::error_1(&format!("Failed to parse channels: {:?}", err).into()); | ||
return JsValue::NULL; | ||
} | ||
}; | ||
|
||
for (key, value) in decoded_data { | ||
let (channel_name, feature_name) = get_channel_and_feature(&key); | ||
match serde_cbor::from_slice::<Value>(data) { | ||
Ok(decoded_value) => { | ||
console::log_1(&format!("Decoded value: {:?}", decoded_value).into()); | ||
if let Value::Map(decoded_map) = decoded_value { | ||
// create output data structures for each graph | ||
let mut psd_data_by_channel: BTreeMap<String, ChannelData> = BTreeMap::new(); | ||
let mut raw_data_by_channel: BTreeMap<String, Value> = BTreeMap::new(); | ||
let mut bandwidth_data_by_channel: BTreeMap<String, BTreeMap<String, Value>> = BTreeMap::new(); | ||
let mut all_data: BTreeMap<String, Value> = BTreeMap::new(); | ||
|
||
if channel_name.is_empty() { | ||
continue; | ||
} | ||
let bandwidth_features = vec![ | ||
"fft_theta_mean", | ||
"fft_alpha_mean", | ||
"fft_low_beta_mean", | ||
"fft_high_beta_mean", | ||
"fft_low_gamma_mean", | ||
"fft_high_gamma_mean", | ||
]; | ||
|
||
if !feature_name.starts_with("fft_psd_") { | ||
continue; | ||
} | ||
for (key_value, value) in decoded_map { | ||
let key_str = match key_value { | ||
Value::Text(s) => s, | ||
_ => continue, | ||
}; | ||
|
||
let feature_number = &feature_name["fft_psd_".len()..]; | ||
let feature_index = match feature_number.parse::<u32>() { | ||
Ok(n) => n, | ||
Err(_) => continue, | ||
}; | ||
// Insert into all_data | ||
all_data.insert(key_str.clone(), value.clone()); | ||
|
||
all_features_set.insert(feature_index); | ||
let (channel_name, feature_name) = | ||
get_channel_and_feature(&key_str, &channels); | ||
|
||
let channel_data = data_by_channel | ||
.entry(channel_name.clone()) | ||
.or_insert_with(|| ChannelData { | ||
channel_name: channel_name.clone(), | ||
feature_map: BTreeMap::new(), | ||
}); | ||
if channel_name.is_empty() { | ||
continue; | ||
} | ||
|
||
channel_data.feature_map.insert(feature_index, value); | ||
} | ||
if feature_name == "raw" { | ||
raw_data_by_channel.insert(channel_name.clone(), value.clone()); | ||
} else if feature_name.starts_with("fft_psd_") { | ||
let feature_number = &feature_name["fft_psd_".len()..]; | ||
let feature_index = match feature_number.parse::<u32>() { | ||
Ok(n) => n, | ||
Err(_) => continue, | ||
}; | ||
|
||
let feature_index_str = feature_index.to_string(); | ||
|
||
let all_features: Vec<u32> = all_features_set.into_iter().collect(); | ||
let channel_data = psd_data_by_channel | ||
.entry(channel_name.clone()) | ||
.or_insert_with(|| ChannelData { | ||
channel_name: channel_name.clone(), | ||
feature_map: BTreeMap::new(), | ||
}); | ||
|
||
let result = ProcessedData { | ||
data_by_channel, | ||
all_features, | ||
}; | ||
channel_data | ||
.feature_map | ||
.insert(feature_index_str, value.clone()); | ||
} else if bandwidth_features.contains(&feature_name.as_str()) { | ||
|
||
to_value(&result).unwrap_or(JsValue::NULL) | ||
let channel_bandwidth_data = bandwidth_data_by_channel | ||
.entry(channel_name.clone()) | ||
.or_insert_with(BTreeMap::new); | ||
|
||
channel_bandwidth_data.insert(feature_name.clone(), value.clone()); | ||
} | ||
} | ||
|
||
let result = ProcessedData { | ||
psd_data_by_channel, | ||
raw_data_by_channel, | ||
bandwidth_data_by_channel, | ||
all_data, | ||
}; | ||
|
||
// Serialize maps as plain JavaScript objects | ||
let serializer = Serializer::new().serialize_maps_as_objects(true); | ||
match result.serialize(&serializer) { | ||
Ok(js_value) => js_value, | ||
Err(err) => { | ||
console::error_1(&format!("Serialization error: {:?}", err).into()); | ||
JsValue::NULL | ||
} | ||
} | ||
} else { | ||
console::error_1(&"Decoded CBOR data is not a map.".into()); | ||
JsValue::NULL | ||
} | ||
} | ||
Err(e) => { | ||
// Optionally log the error for debugging | ||
Err(err) => { | ||
console::error_1(&format!("Failed to decode CBOR data: {:?}", err).into()); | ||
JsValue::NULL | ||
}, | ||
} | ||
} | ||
} | ||
|
||
fn get_channel_and_feature(key: &str) -> (String, String) { | ||
// Adjusted to split at the "_fft_psd_" pattern | ||
let pattern = "_fft_psd_"; | ||
if let Some(pos) = key.find(pattern) { | ||
let channel_name = &key[..pos]; | ||
let feature_name = &key[pos + 1..]; // Skip the underscore | ||
(channel_name.to_string(), feature_name.to_string()) | ||
} else { | ||
("".to_string(), key.to_string()) | ||
fn get_channel_and_feature(key: &str, channels: &[String]) -> (String, String) { | ||
// Iterate over channels to find if the key starts with any channel name | ||
for channel in channels { | ||
if key.starts_with(channel) { | ||
let feature_name = key[channel.len()..].trim_start_matches('_'); | ||
return (channel.clone(), feature_name.to_string()); | ||
} | ||
} | ||
// No matching channel found | ||
("".to_string(), key.to_string()) | ||
} | ||
|
||
#[derive(Serialize)] | ||
struct ChannelData { | ||
channel_name: String, | ||
feature_map: BTreeMap<u32, Value>, | ||
feature_map: BTreeMap<String, Value>, | ||
} | ||
|
||
#[derive(Serialize)] | ||
struct ProcessedData { | ||
data_by_channel: BTreeMap<String, ChannelData>, | ||
all_features: Vec<u32>, | ||
psd_data_by_channel: BTreeMap<String, ChannelData>, | ||
raw_data_by_channel: BTreeMap<String, Value>, | ||
bandwidth_data_by_channel: BTreeMap<String, BTreeMap<String, Value>>, | ||
all_data: BTreeMap<String, Value>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.