From a619e1755a579ce64f20b428e98fde4d1d3737a4 Mon Sep 17 00:00:00 2001 From: BitsAndDroids Date: Fri, 10 Jan 2025 16:59:14 +0100 Subject: [PATCH 1/3] fixed due serial configuration --- .../connector_library/BitsAndDroidsFlightConnector.cpp | 4 +++- .../connector_library/BitsAndDroidsFlightConnector.h | 1 + .../connector/src-tauri/connector_library/library.properties | 2 +- crates/connector/src-tauri/tauri.conf.json | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.cpp b/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.cpp index 2b69d3f..c6d1753 100644 --- a/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.cpp +++ b/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.cpp @@ -13,7 +13,9 @@ BitsAndDroidsFlightConnector::BitsAndDroidsFlightConnector() { BitsAndDroidsFlightConnector::BitsAndDroidsFlightConnector(Serial_ *serial) { this->serial = serial; } -#elif defined(ARDUINO_ARCH_ESP32) || defined(ESP8266) || defined(PICO_RP2040) +#endif +#if defined(ARDUINO_ARCH_ESP32) || defined(ESP8266) || defined(PICO_RP2040) || \ + defined(ARDUINO_SAM_DUE) BitsAndDroidsFlightConnector::BitsAndDroidsFlightConnector( HardwareSerial *serial) { this->serial = &Serial; diff --git a/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.h b/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.h index c7bd7c3..d0db3e4 100644 --- a/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.h +++ b/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.h @@ -644,6 +644,7 @@ class BitsAndDroidsFlightConnector { BitsAndDroidsFlightConnector(); #if defined(ARDUINO_SAM_DUE) BitsAndDroidsFlightConnector(Serial_ *serial); + BitsAndDroidsFlightConnector(HardwareSerial *serial); #elif defined(ESP32) || \ defined( \ ESP8266) // This will handle all boards except ESP32 and Arduino Due diff --git a/crates/connector/src-tauri/connector_library/library.properties b/crates/connector/src-tauri/connector_library/library.properties index 3283803..9498305 100644 --- a/crates/connector/src-tauri/connector_library/library.properties +++ b/crates/connector/src-tauri/connector_library/library.properties @@ -1,5 +1,5 @@ name=Bits and Droids flight sim library -version=1.6.16 +version=1.6.17 author=Bits and Droids maintainer=Bits and Droids sentence=Use serial communication to control Microsoft Flight Simulator 2020. diff --git a/crates/connector/src-tauri/tauri.conf.json b/crates/connector/src-tauri/tauri.conf.json index 8c64a36..89e3c05 100644 --- a/crates/connector/src-tauri/tauri.conf.json +++ b/crates/connector/src-tauri/tauri.conf.json @@ -1,5 +1,5 @@ { - "version": "0.9.10", + "version": "0.9.11", "build": { "beforeDevCommand": "pnpm dev", "beforeBuildCommand": "pnpm run build", From 96221190f1c30bd4a91396050949223e9fbc265e Mon Sep 17 00:00:00 2001 From: Dave <77780263+BitsAndDroids@users.noreply.github.com> Date: Mon, 10 Mar 2025 17:11:31 +0100 Subject: [PATCH 2/3] Vertical speed fix (#305) * Fixed vertical speed variable * added velocitybody to lib --- .../BitsAndDroidsFlightConnector.cpp | 14 +++++++-- .../BitsAndDroidsFlightConnector.h | 6 ++++ .../src-tauri/src/events/outputs.json | 29 ++++++++++++++++++- crates/connector/src-tauri/tauri.conf.json | 2 +- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.cpp b/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.cpp index c6d1753..b1f6ef0 100644 --- a/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.cpp +++ b/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.cpp @@ -516,7 +516,18 @@ void BitsAndDroidsFlightConnector::switchHandling() { trueVerticalSpeed = cutValue.toInt(); break; } - + case 331: { + velocityBodyX = cutValue.toInt(); + break; + } + case 332: { + velocityBodyY = cutValue.toInt(); + break; + } + case 341: { + velocityBodyZ = cutValue.toInt(); + break; + } case 326: { indicatedAirspeed = cutValue.toInt(); break; @@ -529,7 +540,6 @@ void BitsAndDroidsFlightConnector::switchHandling() { indicatedAltitude2 = cutValue.toInt(); break; } - case 337: { kohlmanAltimeter = cutValue.toInt(); break; diff --git a/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.h b/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.h index d0db3e4..53062b0 100644 --- a/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.h +++ b/crates/connector/src-tauri/connector_library/BitsAndDroidsFlightConnector.h @@ -707,6 +707,9 @@ class BitsAndDroidsFlightConnector { int getIndicatedAltitudeCalibrated() { return indicatedAltitudeCalibrated; }; int getIndicatedHeading() { return indicatedHeading; }; int getIndicatedGPSGroundspeed() { return indicatedGPSGroundspeed; }; + int getVelocityBodyX() { return velocityBodyX; }; + int getVelocityBodyY() { return velocityBodyY; }; + int getVelocityBodyZ() { return velocityBodyZ; }; int getTrueVerticalSpeed() { return trueVerticalSpeed; }; int getLastPrefix(); @@ -937,6 +940,9 @@ class BitsAndDroidsFlightConnector { int indicatedAltitudeCalibrated; int indicatedHeading; int indicatedGPSGroundspeed; + int velocityBodyX; + int velocityBodyY; + int velocityBodyZ; int trueVerticalSpeed; int headingGyro; diff --git a/crates/connector/src-tauri/src/events/outputs.json b/crates/connector/src-tauri/src/events/outputs.json index 34394b9..d097432 100644 --- a/crates/connector/src-tauri/src/events/outputs.json +++ b/crates/connector/src-tauri/src/events/outputs.json @@ -469,13 +469,40 @@ }, { "simvar": "VERTICAL SPEED", - "metric": "Feet per second", + "metric": "Feet per minute", "update_every": 10, "cb_text": "Vertical speed", "id": 330, "output_type": "integer", "category": "Data" }, + { + "simvar": "VELOCITY BODY X", + "metric": "Feet per minute", + "update_every": 10, + "cb_text": "Velocity body x", + "id": 331, + "output_type": "integer", + "category": "Data" + }, + { + "simvar": "VELOCITY BODY Y", + "metric": "Feet per minute", + "update_every": 10, + "cb_text": "Velocity body y", + "id": 332, + "output_type": "integer", + "category": "Data" + }, + { + "simvar": "VELOCITY BODY Z", + "metric": "Feet per minute", + "update_every": 10, + "cb_text": "Velocity body z", + "id": 341, + "output_type": "integer", + "category": "Data" + }, { "simvar": "TITLE", "metric": "NULL", diff --git a/crates/connector/src-tauri/tauri.conf.json b/crates/connector/src-tauri/tauri.conf.json index 89e3c05..2abc479 100644 --- a/crates/connector/src-tauri/tauri.conf.json +++ b/crates/connector/src-tauri/tauri.conf.json @@ -1,5 +1,5 @@ { - "version": "0.9.11", + "version": "0.10.0", "build": { "beforeDevCommand": "pnpm dev", "beforeBuildCommand": "pnpm run build", From 5d96eefbb67fb147477f22a89663a98452ea61c0 Mon Sep 17 00:00:00 2001 From: Dave <77780263+BitsAndDroids@users.noreply.github.com> Date: Sat, 12 Apr 2025 14:32:11 +0200 Subject: [PATCH 3/3] Simvarwatcher window added (#307) * added first setup for simvarwatcher * added runbundle event logic * flipped simvar map * added simvar update logic * fixed warnings and removed unused code * made it possible to alter update rate * reset outputs when swapping bundles * allowed decimal input * fixed tests --- .../serial/src/serial/serial_device.rs | 19 +-- .../serial/src/serial/serial_utils.rs | 5 +- crates/connector/src-tauri/src/events.rs | 2 +- .../connector/src-tauri/src/events/action.rs | 20 ++-- .../src-tauri/src/events/action_registry.rs | 2 +- .../connector/src-tauri/src/events/actions.rs | 6 +- .../src-tauri/src/events/input_registry.rs | 4 - .../src-tauri/src/events/output_registry.rs | 4 +- .../src-tauri/src/events/wasm_registry.rs | 24 +--- crates/connector/src-tauri/src/main.rs | 9 +- .../src/settings/settings_actions.rs | 2 +- .../src/simconnect_mod/simconnect_handler.rs | 36 ++++-- .../src-tauri/src/simconnect_mod/wasm.rs | 4 - crates/connector/src-tauri/src/utils.rs | 2 +- .../src-tauri/src/utils/semver_matcher.rs | 10 -- crates/connector/src-tauri/src/utils/store.rs | 14 +++ .../src-tauri/src/utils/wasm_installer.rs | 6 +- crates/connector/src-tauri/tauri.conf.json | 2 +- crates/types/src/lib.rs | 1 + crates/types/src/types/simvar_update.rs | 5 + .../components/ControllerSelectComponent.tsx | 20 +++- frontend/components/nav/MainMenu.tsx | 14 ++- frontend/context/RunStateContext.tsx | 29 ++++- frontend/main.tsx | 5 + frontend/model/Output.ts | 1 + frontend/pages/bundles/OutputsPage.tsx | 18 +-- .../bundles/components/BundleEditor.test.tsx | 3 + .../pages/bundles/components/BundleEditor.tsx | 3 + .../components/OutputSelectRow.stories.tsx | 4 + .../components/OutputSelectRow.test.tsx | 3 + .../bundles/components/OutputSelectRow.tsx | 17 ++- .../components/OutputSelectRows.stories.tsx | 5 + .../components/OutputSelectRows.test.tsx | 2 + .../bundles/components/OutputSelectRows.tsx | 3 + frontend/pages/logs/SimvarWatcher.tsx | 108 ++++++++++++++++++ .../pages/logs/utils/BundleOutputMapper.ts | 13 +++ 36 files changed, 321 insertions(+), 104 deletions(-) delete mode 100644 crates/connector/src-tauri/src/utils/semver_matcher.rs create mode 100644 crates/connector/src-tauri/src/utils/store.rs create mode 100644 crates/types/src/types/simvar_update.rs create mode 100644 frontend/pages/logs/SimvarWatcher.tsx create mode 100644 frontend/pages/logs/utils/BundleOutputMapper.ts diff --git a/crates/connector/serial/src/serial/serial_device.rs b/crates/connector/serial/src/serial/serial_device.rs index a43d5f3..f7a8d6f 100644 --- a/crates/connector/serial/src/serial/serial_device.rs +++ b/crates/connector/serial/src/serial/serial_device.rs @@ -21,10 +21,7 @@ pub trait Serial { impl Serial for SerialDevice { fn new(device_name: String, trs: bool) -> Result { - let ports = match serialport::available_ports() { - Ok(ports) => ports, - Err(_) => Vec::new(), - }; + let ports = serialport::available_ports().unwrap_or_else(|_| Vec::new()); let ports_output = ports .iter() .map(|port| { @@ -91,10 +88,16 @@ impl Serial for SerialDevice { } } fn write(&mut self, data: &[u8]) { - match self.port.write_all(data) { - Ok(_) => {} - Err(e) => { - error!(target: "connections", "Failed to send data: {}", e); + let mut remaining_data = data; + while !remaining_data.is_empty() { + match self.port.write(remaining_data) { + Ok(written) => { + remaining_data = &remaining_data[written..]; + } + Err(e) => { + error!(target: "connections", "Failed to send data: {}", e); + break; + } } } } diff --git a/crates/connector/serial/src/serial/serial_utils.rs b/crates/connector/serial/src/serial/serial_utils.rs index 1c4bfef..5e15112 100644 --- a/crates/connector/serial/src/serial/serial_utils.rs +++ b/crates/connector/serial/src/serial/serial_utils.rs @@ -1,10 +1,7 @@ use serialport::SerialPortType; pub fn get_serial_devices() -> Vec { - let ports = match serialport::available_ports() { - Ok(ports) => ports, - Err(_) => Vec::new(), - }; + let ports = serialport::available_ports().unwrap_or_else(|_| Vec::new()); let ports_output = ports .iter() .map(|port| { diff --git a/crates/connector/src-tauri/src/events.rs b/crates/connector/src-tauri/src/events.rs index 135bd17..8109b9a 100644 --- a/crates/connector/src-tauri/src/events.rs +++ b/crates/connector/src-tauri/src/events.rs @@ -24,7 +24,7 @@ pub async fn get_wasm_events(app: tauri::AppHandle) -> Vec { pub async fn get_latest_custom_event_version(app: tauri::AppHandle) -> String { let mut wasm_registry = events::wasm_registry::WASMRegistry::new(); wasm_registry.load_wasm(&app); - wasm_registry.get_latest_custom_event_version(&app) + wasm_registry.get_latest_custom_event_version() } #[tauri::command] diff --git a/crates/connector/src-tauri/src/events/action.rs b/crates/connector/src-tauri/src/events/action.rs index 9bea27f..6b51f52 100644 --- a/crates/connector/src-tauri/src/events/action.rs +++ b/crates/connector/src-tauri/src/events/action.rs @@ -1,20 +1,20 @@ use simconnect::SimConnector; pub struct Action { - pub id: u32, - pub name: ActionName, + pub _id: u32, + pub _name: ActionName, pub excecute_action: Box, } impl Action { pub const fn new( - id: u32, - name: ActionName, + _id: u32, + _name: ActionName, excecute_action: Box, ) -> Action { Action { - id, - name, + _id, + _name, excecute_action, } } @@ -31,9 +31,7 @@ impl Action { } pub enum ActionName { - THROTTLE, - PROP, - MIXTURE, - RUDDER, - AILERON, + Throttle, + Prop, + Mixture, } diff --git a/crates/connector/src-tauri/src/events/action_registry.rs b/crates/connector/src-tauri/src/events/action_registry.rs index e714a9c..bfc936d 100644 --- a/crates/connector/src-tauri/src/events/action_registry.rs +++ b/crates/connector/src-tauri/src/events/action_registry.rs @@ -20,6 +20,6 @@ impl ActionRegistry { } pub fn get_action_by_id(&self, id: u32) -> Option<&Action> { - return self.actions.get(&id); + self.actions.get(&id) } } diff --git a/crates/connector/src-tauri/src/events/actions.rs b/crates/connector/src-tauri/src/events/actions.rs index da1cc39..2a4bc9e 100644 --- a/crates/connector/src-tauri/src/events/actions.rs +++ b/crates/connector/src-tauri/src/events/actions.rs @@ -67,15 +67,15 @@ pub fn get_actions() -> HashMap { let mut action_map = HashMap::new(); action_map.insert( 199, - Action::new(199, ActionName::THROTTLE, Box::new(throttle_action)), + Action::new(199, ActionName::Throttle, Box::new(throttle_action)), ); action_map.insert( 115, - Action::new(115, ActionName::MIXTURE, Box::new(mixture_action)), + Action::new(115, ActionName::Mixture, Box::new(mixture_action)), ); action_map.insert( 198, - Action::new(198, ActionName::PROP, Box::new(propeller_action)), + Action::new(198, ActionName::Prop, Box::new(propeller_action)), ); action_map } diff --git a/crates/connector/src-tauri/src/events/input_registry.rs b/crates/connector/src-tauri/src/events/input_registry.rs index 4014726..48ccad6 100644 --- a/crates/connector/src-tauri/src/events/input_registry.rs +++ b/crates/connector/src-tauri/src/events/input_registry.rs @@ -23,10 +23,6 @@ impl InputRegistry { } } - pub fn get_inputs(&self) -> &HashMap { - &self.inputs - } - pub fn get_input(&self, input_id: u32) -> Option<&Input> { self.inputs.get(&input_id) } diff --git a/crates/connector/src-tauri/src/events/output_registry.rs b/crates/connector/src-tauri/src/events/output_registry.rs index 3bf016f..7443c71 100644 --- a/crates/connector/src-tauri/src/events/output_registry.rs +++ b/crates/connector/src-tauri/src/events/output_registry.rs @@ -1,11 +1,10 @@ use std::collections::HashMap; -use connector_types::types::{category::Category, output::Output, wasm_event::WasmEvent}; +use connector_types::types::{output::Output, wasm_event::WasmEvent}; use file_parsers::parsers::output_parser; #[derive(Clone, Debug)] pub struct OutputRegistry { - pub categories: Vec, pub outputs: HashMap, output_path: String, } @@ -13,7 +12,6 @@ pub struct OutputRegistry { impl OutputRegistry { pub fn new() -> OutputRegistry { OutputRegistry { - categories: Vec::new(), outputs: HashMap::new(), output_path: String::from("src/events/outputs.json"), } diff --git a/crates/connector/src-tauri/src/events/wasm_registry.rs b/crates/connector/src-tauri/src/events/wasm_registry.rs index 109f4c6..406a9c3 100644 --- a/crates/connector/src-tauri/src/events/wasm_registry.rs +++ b/crates/connector/src-tauri/src/events/wasm_registry.rs @@ -4,7 +4,7 @@ use connector_types::types::{output::Output, wasm_event::WasmEvent}; use serde_json::json; use tauri_plugin_store::StoreExt; -use crate::simconnect_mod::wasm::send_wasm_command; +use crate::{simconnect_mod::wasm::send_wasm_command, utils::store::save_store}; #[derive(Debug, Clone)] pub struct WASMRegistry { wasm_outputs: HashMap, @@ -37,11 +37,11 @@ impl WASMRegistry { for event in &self.wasm_default_events { store.set(event.id.to_string().clone(), json!(event)); } - store.save(); + save_store(store); self.load_wasm(&app); } - pub fn get_latest_custom_event_version(&mut self, app: &tauri::AppHandle) -> String { + pub fn get_latest_custom_event_version(&mut self) -> String { let parsed_custom_event_file = file_parsers::parsers::wasm_event_parser::parse_events_from_file(&self.wasm_file_path); parsed_custom_event_file.version @@ -64,11 +64,7 @@ impl WASMRegistry { self.wasm_inputs.insert(wasm_event.id, wasm_event); } } - store.save(); - } - - pub fn get_wasm_output_by_id(&mut self, output_id: u32) -> Option<&Output> { - self.parsed_wasm_outputs.get(&output_id) + save_store(store); } pub fn get_wasm_event_by_id(&self, event_id: u32) -> Option<&WasmEvent> { @@ -79,10 +75,6 @@ impl WASMRegistry { &self.wasm_outputs } - pub fn get_wasm_inputs(&self) -> &HashMap { - &self.wasm_inputs - } - pub fn get_wasm_events(&self) -> HashMap { let mut events = self.wasm_outputs.clone(); events.extend(self.wasm_inputs.clone()); @@ -93,12 +85,6 @@ impl WASMRegistry { self.wasm_default_events.clone() } - pub fn set_wasm_output_value(&mut self, output_id: u32, value: f64) { - if let Some(output) = self.wasm_outputs.get_mut(&output_id) { - output.value = value; - } - } - pub fn init_custom_events_to_store(&mut self, app: &tauri::AppHandle) { let store = app.store(".events.dat").unwrap(); self.load_default_events(); @@ -106,7 +92,7 @@ impl WASMRegistry { for event in events { store.set(event.id.to_string().clone(), json!(event)); } - store.save(); + save_store(store); } pub fn register_wasm_inputs_to_simconnect(&self, conn: &mut simconnect::SimConnector) { diff --git a/crates/connector/src-tauri/src/main.rs b/crates/connector/src-tauri/src/main.rs index cf498e6..f32bd38 100644 --- a/crates/connector/src-tauri/src/main.rs +++ b/crates/connector/src-tauri/src/main.rs @@ -27,6 +27,7 @@ use utils::library_handler::generate_library; use utils::library_handler::get_library_header_content; use utils::library_handler::get_library_outputs; use utils::library_handler::get_library_source_content; +use utils::store::save_store; use utils::wasm_installer::{check_if_wasm_up_to_date, install_wasm}; use std::{env, thread}; @@ -106,14 +107,14 @@ async fn get_outputs(app: tauri::AppHandle) -> Vec { } #[tauri::command] -fn send_debug_message(app: tauri::AppHandle, message: Message) { +fn send_debug_message(message: Message) { println!("Received message: {:?}", message); let sender = SENDER.lock().unwrap().deref().clone().unwrap(); sender.send(message).unwrap(); } #[tauri::command] -fn start_simconnect_connection(app: tauri::AppHandle, run_bundles: Vec, debug: bool) { +fn start_simconnect_connection(app: tauri::AppHandle, run_bundles: Vec) { let (tx, rx) = mpsc::channel(); *SENDER.lock().unwrap() = Some(tx); *RECEIVER.lock().unwrap() = Some(rx); @@ -122,7 +123,7 @@ fn start_simconnect_connection(app: tauri::AppHandle, run_bundles: Vec path, - Err(e) => { + Err(_) => { return Err(std::io::Error::new( std::io::ErrorKind::NotFound, "Failed to resolve exe.xml resource path", diff --git a/crates/connector/src-tauri/src/simconnect_mod/simconnect_handler.rs b/crates/connector/src-tauri/src/simconnect_mod/simconnect_handler.rs index baf0309..5e6e475 100644 --- a/crates/connector/src-tauri/src/simconnect_mod/simconnect_handler.rs +++ b/crates/connector/src-tauri/src/simconnect_mod/simconnect_handler.rs @@ -1,5 +1,6 @@ use connector_types::types::connector_settings::ConnectorSettings; use connector_types::types::input::InputType; +use connector_types::types::simvar_update::SimvarUpdate; use lazy_static::lazy_static; use log::warn; use log::{error, info}; @@ -80,17 +81,10 @@ pub struct SimconnectHandler { active_com_ports: HashMap>, run_bundles: Vec, connector_settings: ConnectorSettings, - debug: bool, -} - -// define the payload struct -#[derive(Clone, serde::Serialize)] -struct Payload { - message: String, } impl SimconnectHandler { - pub fn new(app_handle: tauri::AppHandle, rx: mpsc::Receiver, debug: bool) -> Self { + pub fn new(app_handle: tauri::AppHandle, rx: mpsc::Receiver) -> Self { let mut simconnect = simconnect::SimConnector::new(); simconnect.connect("Tauri Simconnect"); let input_registry = InputRegistry::new(); @@ -110,7 +104,6 @@ impl SimconnectHandler { active_com_ports: HashMap::new(), run_bundles: vec![], connector_settings, - debug, } } @@ -171,6 +164,10 @@ impl SimconnectHandler { pub fn start_connection(&mut self, run_bundles: Vec) { self.run_bundles = run_bundles; + println!( + "Starting connection with run bundles: {:?}", + self.run_bundles + ); self.set_settings(); self.set_com_ports(); self.connect_to_devices(); @@ -265,6 +262,15 @@ impl SimconnectHandler { }) .collect(); + self.app_handle + .emit( + "simvar_update", + SimvarUpdate { + id: output_id, + value, + }, + ) + .expect("Something went wrong emitting value"); for com_port in com_ports { self.send_output_to_device(output_exists.1, &com_port, value); } @@ -275,6 +281,16 @@ impl SimconnectHandler { "Sending output to device: {}, {}, {}", output_id, com_port, value ); + self.app_handle + .emit_to( + "logWindow", + "simvar_update", + SimvarUpdate { + id: output_id, + value, + }, + ) + .expect("Something went wrong emitting value"); // Mutably borrow self.output_registry to set the value // TODO: refactor to return result instead @@ -573,7 +589,7 @@ impl SimconnectHandler { &latest_output.metric, simconnect::SIMCONNECT_DATATYPE_SIMCONNECT_DATATYPE_FLOAT64, latest_output.id, - latest_output.update_every, + output.update_every, ); } } diff --git a/crates/connector/src-tauri/src/simconnect_mod/wasm.rs b/crates/connector/src-tauri/src/simconnect_mod/wasm.rs index 0bc3fa9..e852d06 100644 --- a/crates/connector/src-tauri/src/simconnect_mod/wasm.rs +++ b/crates/connector/src-tauri/src/simconnect_mod/wasm.rs @@ -13,7 +13,6 @@ struct ClientDataProperties { id: u32, name: &'static str, definition_id: u32, - request_id: u32, data_size: DWORD, } @@ -22,7 +21,6 @@ pub fn register_wasm_data(conn: &mut simconnect::SimConnector) { id: 1, name: "shared", definition_id: 101, - request_id: 102, data_size: 256, }; create_wasm_client(conn, &mut input_client); @@ -31,7 +29,6 @@ pub fn register_wasm_data(conn: &mut simconnect::SimConnector) { id: 2, name: "messages", definition_id: 103, - request_id: 104, data_size: 4096, }; create_wasm_client(conn, &mut output_client); @@ -40,7 +37,6 @@ pub fn register_wasm_data(conn: &mut simconnect::SimConnector) { id: 3, name: "command_client", definition_id: 105, - request_id: 106, data_size: 4096, }; create_wasm_client(conn, &mut command_client); diff --git a/crates/connector/src-tauri/src/utils.rs b/crates/connector/src-tauri/src/utils.rs index 87d24ca..b290606 100644 --- a/crates/connector/src-tauri/src/utils.rs +++ b/crates/connector/src-tauri/src/utils.rs @@ -1,3 +1,3 @@ pub mod library_handler; -pub mod semver_matcher; +pub mod store; pub mod wasm_installer; diff --git a/crates/connector/src-tauri/src/utils/semver_matcher.rs b/crates/connector/src-tauri/src/utils/semver_matcher.rs deleted file mode 100644 index 2eeaa1f..0000000 --- a/crates/connector/src-tauri/src/utils/semver_matcher.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub fn check_newer_version_available(old: &str, new: &str) -> bool { - let old = old.split('.').collect::>(); - let new = new.split('.').collect::>(); - for i in 0..old.len() { - if old[i].parse::().unwrap() < new[i].parse::().unwrap() { - return true; - } - } - false -} diff --git a/crates/connector/src-tauri/src/utils/store.rs b/crates/connector/src-tauri/src/utils/store.rs new file mode 100644 index 0000000..c9725e6 --- /dev/null +++ b/crates/connector/src-tauri/src/utils/store.rs @@ -0,0 +1,14 @@ +use std::sync::Arc; + +use tauri::Wry; + +pub fn save_store(store: Arc>) { + match store.save() { + Ok(_) => { + println!("Store saved"); + } + Err(e) => { + println!("Failed to save store: {:?}", e); + } + } +} diff --git a/crates/connector/src-tauri/src/utils/wasm_installer.rs b/crates/connector/src-tauri/src/utils/wasm_installer.rs index aa2a42e..0543f5b 100644 --- a/crates/connector/src-tauri/src/utils/wasm_installer.rs +++ b/crates/connector/src-tauri/src/utils/wasm_installer.rs @@ -1,9 +1,9 @@ -use std::path::Path; - use log::error; use serde_json::json; use tauri_plugin_store::StoreExt; +use super::store::save_store; + #[tauri::command] pub fn install_wasm(app: tauri::AppHandle) { let exe_path = std::env::current_dir().unwrap(); @@ -23,7 +23,7 @@ pub fn install_wasm(app: tauri::AppHandle) { println!("Community folder path: {:?}", community_folder_path); store.set("installedWASMVersion".to_owned(), json!(version)) } - store.save(); + save_store(store); let files = return_files_in_dir(wasm_path.to_str().unwrap()); for file in files { diff --git a/crates/connector/src-tauri/tauri.conf.json b/crates/connector/src-tauri/tauri.conf.json index 2abc479..3279b6f 100644 --- a/crates/connector/src-tauri/tauri.conf.json +++ b/crates/connector/src-tauri/tauri.conf.json @@ -1,5 +1,5 @@ { - "version": "0.10.0", + "version": "0.11.0", "build": { "beforeDevCommand": "pnpm dev", "beforeBuildCommand": "pnpm run build", diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 5f21c54..e63a41c 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -9,5 +9,6 @@ pub mod types { pub mod output; pub mod output_format; pub mod run_bundle; + pub mod simvar_update; pub mod wasm_event; } diff --git a/crates/types/src/types/simvar_update.rs b/crates/types/src/types/simvar_update.rs new file mode 100644 index 0000000..99e37f3 --- /dev/null +++ b/crates/types/src/types/simvar_update.rs @@ -0,0 +1,5 @@ +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct SimvarUpdate { + pub id: u32, + pub value: f64, +} diff --git a/frontend/components/ControllerSelectComponent.tsx b/frontend/components/ControllerSelectComponent.tsx index 46898cf..dfa718a 100644 --- a/frontend/components/ControllerSelectComponent.tsx +++ b/frontend/components/ControllerSelectComponent.tsx @@ -7,13 +7,12 @@ import { useState, } from "react"; import { invoke } from "#tauri/invoke"; -import { Bundle } from "@/model/Bundle"; import { Preset } from "@/model/Preset"; import { ControllerSelect } from "./ControllerSelect"; import { BundleSettingsHandler } from "@/utils/BundleSettingsHandler"; import { RunSettingsHandler } from "@/utils/runSettingsHandler"; import { PresetSettingsHandler } from "@/utils/PresetSettingsHandler"; -import { listen } from "@tauri-apps/api/event"; +import { emit, emitTo, listen } from "@tauri-apps/api/event"; import { RunBundlePopulated, populateRunBundles } from "@/model/RunBundle"; import PresetControls from "./presets/PresetControls"; import { RunStateContext } from "#context/RunStateContext.js"; @@ -25,6 +24,7 @@ async function invokeConnection( if (!preset) { return; } + await emitTo("logWindow", "runbundles_active", { runBundles: runBundles }); if (process.env.NODE_ENV !== "production") { invoke("start_simconnect_connection", { runBundles: runBundles, @@ -64,8 +64,13 @@ export const ControllerSelectComponent = () => { const runSettingsHandler = useRef(new RunSettingsHandler()); const context = useContext(RunStateContext); - const { connectionRunning, setConnectionRunning, bundles, setBundles } = - context; + const { + connectionRunning, + setConnectionRunning, + bundles, + setBundles, + setCurrentRunBundle, + } = context; const [loaded, setLoaded] = useState(false); const [comPorts, setComPorts] = useState([]); @@ -120,9 +125,14 @@ export const ControllerSelectComponent = () => { startEventListeners(); runSettingsHandler.current.setLastPresetId(preset.id); + const populatedRunbundleArray = await populateRunBundles( + preset.runBundles, + ); + console.log(populatedRunbundleArray); + setCurrentRunBundle(populatedRunbundleArray); await invokeConnection( preset, - await populateRunBundles(preset.runBundles), + populatedRunbundleArray as RunBundlePopulated[], ); } setConnectionRunning(!connectionRunning); diff --git a/frontend/components/nav/MainMenu.tsx b/frontend/components/nav/MainMenu.tsx index bd6e85a..b1c8d20 100644 --- a/frontend/components/nav/MainMenu.tsx +++ b/frontend/components/nav/MainMenu.tsx @@ -3,7 +3,7 @@ import { WebviewWindow } from "@tauri-apps/api/webviewWindow"; import { Outlet } from "react-router-dom"; import { TopMenuItem } from "@/components/nav/TopMenuItem"; import { FileDialog } from "../dialogs/file/FileDialog"; -import { useContext, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { invoke } from "@tauri-apps/api/core"; import { ConnectorSettingsHandler } from "@/utils/connectorSettingsHandler"; import { generateLibrary } from "@/library/utils/CustomWasmGenerator"; @@ -48,6 +48,13 @@ export const MainMenu: React.FC = () => { title: "Logs", }); } + function openSimvarWatchWindow() { + //TODO: pass data of runbundle state to window using events + const webView = new WebviewWindow("logWindow", { + url: "/logs/simvarWatcher", + title: "Simvar Watcher", + }); + } const openEventTestWindow = async () => { new WebviewWindow("eventTestWindow", { @@ -93,6 +100,11 @@ export const MainMenu: React.FC = () => { ]; const debugmenuItems = [ { title: "Logs", action: () => openLogWindow(), active: true }, + { + title: "Simvar watcher", + action: () => openSimvarWatchWindow(), + active: true, + }, { title: "Test events", action: () => openEventTestWindow(), active: true }, ]; diff --git a/frontend/context/RunStateContext.tsx b/frontend/context/RunStateContext.tsx index 43f68af..0653c8a 100644 --- a/frontend/context/RunStateContext.tsx +++ b/frontend/context/RunStateContext.tsx @@ -1,4 +1,5 @@ import { Bundle } from "#model/Bundle.js"; +import { RunBundlePopulated } from "#model/RunBundle.js"; import { createContext, Dispatch, SetStateAction, useState } from "react"; export const RunStateContext = createContext<{ @@ -6,11 +7,22 @@ export const RunStateContext = createContext<{ setConnectionRunning: Dispatch>; bundles: Array; setBundles: Dispatch>>; + currentRunBundle: Array; + setCurrentRunBundle: Dispatch>>; }>({ connectionRunning: false, setConnectionRunning: () => {}, bundles: [], setBundles: () => {}, + currentRunBundle: [ + { + id: 0, + com_port: "", + connected: false, + bundle: { name: "", version: 0 }, + }, + ], + setCurrentRunBundle: () => {}, }); export const RunStateContextProvider = ({ @@ -19,10 +31,25 @@ export const RunStateContextProvider = ({ children: React.ReactNode; }) => { const [connectionRunning, setConnectionRunning] = useState(false); + const [currentRunBundle, setCurrentRunBundle] = useState([ + { + id: 0, + com_port: "", + connected: false, + bundle: { name: "", version: 0 }, + }, + ]); const [bundles, setBundles] = useState>([]); return ( {children} diff --git a/frontend/main.tsx b/frontend/main.tsx index dfb589c..207dd8d 100644 --- a/frontend/main.tsx +++ b/frontend/main.tsx @@ -10,6 +10,7 @@ import { PresetManagerPage } from "./pages/options/settings/PresetManagerPage"; import { CustomEvents } from "./pages/custom_output_page/CustomEvents"; import { RunStateContextProvider } from "#context/RunStateContext.js"; import { TestPage } from "#pages/test_page/TestPage.js"; +import { SimvarWatcher } from "#pages/logs/SimvarWatcher.js"; const router = createBrowserRouter([ { path: "/", @@ -43,6 +44,10 @@ const router = createBrowserRouter([ path: "/logs", element: , }, + { + path: "/logs/simvarWatcher", + element: , + }, { path: "/event-test", element: , diff --git a/frontend/model/Output.ts b/frontend/model/Output.ts index af29db5..52c2f05 100644 --- a/frontend/model/Output.ts +++ b/frontend/model/Output.ts @@ -7,6 +7,7 @@ export interface Output { output_type: string; category: string; selected?: boolean; + value?: string; } export const OutputFormats = [ { value: "integer", label: "Integer (1)" }, diff --git a/frontend/pages/bundles/OutputsPage.tsx b/frontend/pages/bundles/OutputsPage.tsx index 5b5c996..31cf0dc 100644 --- a/frontend/pages/bundles/OutputsPage.tsx +++ b/frontend/pages/bundles/OutputsPage.tsx @@ -69,6 +69,10 @@ const OutputsPage: React.FC = () => { return outputsToSearch; } + function changeUpdateRate(output: Output) { + setOutputs(outputs.map((o) => (o.id === output.id ? output : o))); + } + function dialogResult(input: string | undefined) { if (input !== undefined) { const bundle: Bundle = { @@ -82,17 +86,13 @@ const OutputsPage: React.FC = () => { setDialogOpen(false); } - function resetOutputs() { - let outputState = [...outputs]; - for (let output of outputState) { - output.selected = false; - } - setOutputs(outputState); + async function resetOutputs() { + setOutputs(await getOutputs()); } - function setEditBundleState(editBundle: Bundle) { + async function setEditBundleState(editBundle: Bundle) { setEditMode(true); - resetOutputs(); + await resetOutputs(); let outputState = [...outputs]; if (!editBundle.outputs) { return; @@ -101,6 +101,7 @@ const OutputsPage: React.FC = () => { for (let o of outputState) { if (o.id === output.id) { o.selected = true; + o.update_every = output.update_every; } } } @@ -154,6 +155,7 @@ const OutputsPage: React.FC = () => { outputs={outputs} toggleOutput={toggleOutput} dialogOpen={dialogOpen} + changeUpdateRate={changeUpdateRate} /> )} diff --git a/frontend/pages/bundles/components/BundleEditor.test.tsx b/frontend/pages/bundles/components/BundleEditor.test.tsx index b422f8d..bb75338 100644 --- a/frontend/pages/bundles/components/BundleEditor.test.tsx +++ b/frontend/pages/bundles/components/BundleEditor.test.tsx @@ -12,6 +12,9 @@ describe("BundleEditor", () => { toggleOutput={function (output: Output): void { throw new Error("Function not implemented."); }} + changeUpdateRate={function (output: Output): void { + throw new Error("Function not implemented."); + }} />, ); expect(container).toBeTruthy(); diff --git a/frontend/pages/bundles/components/BundleEditor.tsx b/frontend/pages/bundles/components/BundleEditor.tsx index 2909564..823296f 100644 --- a/frontend/pages/bundles/components/BundleEditor.tsx +++ b/frontend/pages/bundles/components/BundleEditor.tsx @@ -12,12 +12,14 @@ interface BundleEditorProps { outputs: Output[]; dialogOpen: boolean; toggleOutput: (output: Output) => void; + changeUpdateRate: (output: Output) => void; } const BundleEditor = ({ outputs, dialogOpen, toggleOutput, + changeUpdateRate, }: BundleEditorProps) => { let categories = new Map(); for (let output of outputs) { @@ -105,6 +107,7 @@ const BundleEditor = ({ outputs={filteredOutputs} dialogOpen={dialogOpen} toggleOutput={toggleOutput} + changeUpdateRate={changeUpdateRate} /> diff --git a/frontend/pages/bundles/components/OutputSelectRow.stories.tsx b/frontend/pages/bundles/components/OutputSelectRow.stories.tsx index 4c2d69a..f4aafd8 100644 --- a/frontend/pages/bundles/components/OutputSelectRow.stories.tsx +++ b/frontend/pages/bundles/components/OutputSelectRow.stories.tsx @@ -25,12 +25,16 @@ const OutputSelectRowWithHooks = () => { setToggleOutput(output); setOutputs({ ...output, selected: !output.selected }); }; + const changeUpdateRate = (output: any) => { + setOutputs({ ...output, update_every: output.update_every }); + }; return ( ); }; diff --git a/frontend/pages/bundles/components/OutputSelectRow.test.tsx b/frontend/pages/bundles/components/OutputSelectRow.test.tsx index 05c9c4d..0113aeb 100644 --- a/frontend/pages/bundles/components/OutputSelectRow.test.tsx +++ b/frontend/pages/bundles/components/OutputSelectRow.test.tsx @@ -22,6 +22,7 @@ describe("OutputSelectRow", () => { index={0} dialogOpen={false} toggleOutput={() => {}} + changeUpdateRate={() => {}} />, ); expect(container).toBeTruthy(); @@ -34,6 +35,7 @@ describe("OutputSelectRow", () => { index={0} dialogOpen={true} toggleOutput={() => {}} + changeUpdateRate={() => {}} />, ); expect(container).toBeTruthy(); @@ -48,6 +50,7 @@ describe("OutputSelectRow", () => { index={0} dialogOpen={false} toggleOutput={() => {}} + changeUpdateRate={() => {}} />, ); expect(container).toBeTruthy(); diff --git a/frontend/pages/bundles/components/OutputSelectRow.tsx b/frontend/pages/bundles/components/OutputSelectRow.tsx index 0937f7d..711ab22 100644 --- a/frontend/pages/bundles/components/OutputSelectRow.tsx +++ b/frontend/pages/bundles/components/OutputSelectRow.tsx @@ -1,9 +1,11 @@ +import { Input } from "#components/elements/inputs/Input.js"; import { Output } from "@/model/Output"; interface CategoryCheckboxesProps { output: Output; index: number; dialogOpen: boolean; toggleOutput: (output: Output) => void; + changeUpdateRate: (output: Output) => void; } export const OutputSelectRow = ({ @@ -11,6 +13,7 @@ export const OutputSelectRow = ({ index, dialogOpen, toggleOutput, + changeUpdateRate, }: CategoryCheckboxesProps) => { return (
@@ -61,7 +64,19 @@ export const OutputSelectRow = ({ alt="update_every" /> -

{output.update_every}

+ + changeUpdateRate({ + ...output, + update_every: parseFloat(value as string), + }) + } + /> + + {/*

{output.update_every}

*/}
diff --git a/frontend/pages/bundles/components/OutputSelectRows.stories.tsx b/frontend/pages/bundles/components/OutputSelectRows.stories.tsx index d42740b..d1a9258 100644 --- a/frontend/pages/bundles/components/OutputSelectRows.stories.tsx +++ b/frontend/pages/bundles/components/OutputSelectRows.stories.tsx @@ -80,11 +80,16 @@ const OutputSelectRowsWithHooks = () => { output.selected = !output.selected; setOutputs([...outputs]); }; + const changeUpdateRate = (output: any) => { + output.update_every = output.update_every; + setOutputs([...outputs]); + }; return ( ); }; diff --git a/frontend/pages/bundles/components/OutputSelectRows.test.tsx b/frontend/pages/bundles/components/OutputSelectRows.test.tsx index 0b2e465..fe72887 100644 --- a/frontend/pages/bundles/components/OutputSelectRows.test.tsx +++ b/frontend/pages/bundles/components/OutputSelectRows.test.tsx @@ -33,6 +33,7 @@ describe("OutputSelectRows", () => { outputs={mockOutputs} dialogOpen={false} toggleOutput={(_output: Output) => {}} + changeUpdateRate={(_output: Output) => {}} />, ); expect(container).toBeTruthy(); @@ -45,6 +46,7 @@ describe("OutputSelectRows", () => { outputs={mockOutputs} dialogOpen={false} toggleOutput={(_output: Output) => {}} + changeUpdateRate={(_output: Output) => {}} />, ); expect(container).toBeTruthy(); diff --git a/frontend/pages/bundles/components/OutputSelectRows.tsx b/frontend/pages/bundles/components/OutputSelectRows.tsx index fa90d55..5710782 100644 --- a/frontend/pages/bundles/components/OutputSelectRows.tsx +++ b/frontend/pages/bundles/components/OutputSelectRows.tsx @@ -4,12 +4,14 @@ interface CategoryCheckboxesProps { outputs: Output[]; dialogOpen: boolean; toggleOutput: (output: Output) => void; + changeUpdateRate: (output: Output) => void; } export const OutputSelectRows = ({ outputs, dialogOpen, toggleOutput, + changeUpdateRate, }: CategoryCheckboxesProps) => { return (
@@ -20,6 +22,7 @@ export const OutputSelectRows = ({ index={index} dialogOpen={dialogOpen} toggleOutput={toggleOutput} + changeUpdateRate={changeUpdateRate} /> ))}
diff --git a/frontend/pages/logs/SimvarWatcher.tsx b/frontend/pages/logs/SimvarWatcher.tsx new file mode 100644 index 0000000..e75762a --- /dev/null +++ b/frontend/pages/logs/SimvarWatcher.tsx @@ -0,0 +1,108 @@ +import { RunStateContext } from "#context/RunStateContext.js"; +import { Output } from "#model/Output.js"; +import { RunBundlePopulated } from "#model/RunBundle.js"; +import { invoke } from "@tauri-apps/api/core"; +import { listen } from "@tauri-apps/api/event"; +import { useContext, useEffect, useState } from "react"; + +interface simvar_update_message { + id: number; + value: number; +} + +const createSimvarTable = async (vars: Map) => { + let outputs = await getOutputs(); + let table = document.createElement("table"); + vars.keys().forEach((outputID) => { + let output: Output | undefined = outputs.find((o) => o.id === outputID); + if (!output) { + return; + } + table.appendChild(createSimvarRow(output)); + }); +}; + +async function getOutputs() { + return invoke("get_outputs").then((r) => { + return r as Output[]; + }); +} + +const createSimvarRow = (output: Output) => { + let row = document.createElement("tr"); + let simvarCell = document.createElement("td"); + simvarCell.textContent = output.simvar.toString(); + let valueCell = document.createElement("td"); + valueCell.textContent = ""; + row.appendChild(simvarCell); + row.appendChild(valueCell); + return row; +}; + +export const SimvarWatcher: React.FC = () => { + const [runBundles, setRunBundles] = useState>([]); + const [simvarMap, setSimvarMap] = useState>( + new Map(), + ); + + useEffect(() => { + const initSimvarMap = async () => { + const outputsInBundle: Output[] = + runBundles.flatMap((bundle) => bundle?.bundle?.outputs || []) || []; + let outputMap = new Map(); + outputsInBundle.forEach((output) => { + outputMap.set(output.id, output); + }); + setSimvarMap(outputMap); + }; + const handleOutputInvocations = async () => { + const unlisten = await listen("runbundles_active", ({ payload }) => { + console.log("outputs_active", payload); + setRunBundles(payload.runBundles); + }); + return unlisten; + }; + const handleSimvarUpdate = async () => { + const unlisten = await listen("simvar_update", ({ payload }) => { + console.log("simvar_update", payload); + setSimvarMap((prevmap) => + new Map(prevmap).set(payload.id, { + ...prevmap.get(payload.id)!, + value: payload.value, + }), + ); + }); + return unlisten; + }; + + const unsubscribe = handleSimvarUpdate(); + const unsubscribeOutputsListener = handleOutputInvocations(); + initSimvarMap(); + return () => { + unsubscribe.then((fn) => fn()); + unsubscribeOutputsListener.then((fn) => fn()); + }; + }, [runBundles]); + + return ( +
+

+ Simvar watcher +

+
+
+ + + {Array.from(simvarMap.entries()).map(([id, output]) => ( + + + + + ))} + +
{output?.simvar}{output.value}
+
+
+
+ ); +}; diff --git a/frontend/pages/logs/utils/BundleOutputMapper.ts b/frontend/pages/logs/utils/BundleOutputMapper.ts new file mode 100644 index 0000000..b285452 --- /dev/null +++ b/frontend/pages/logs/utils/BundleOutputMapper.ts @@ -0,0 +1,13 @@ +import { RunBundlePopulated } from "#model/RunBundle.js"; + +export const mapBundleArrayOutputsToMap = ( + bundles: RunBundlePopulated[], +): Map => { + const outputMap = new Map(); + bundles.forEach((bundle) => { + bundle.bundle?.outputs?.forEach((output) => { + outputMap.set(output.simvar, ""); + }); + }); + return outputMap; +};