mirror of
https://github.com/cjfranko/NTP-Timeturner.git
synced 2025-11-08 18:32:02 +00:00
Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
98 lines
2.7 KiB
Rust
98 lines
2.7 KiB
Rust
// src/main.rs
|
||
|
||
|
||
mod config;
|
||
mod ptp;
|
||
mod serial_input;
|
||
mod sync_logic;
|
||
mod ui;
|
||
|
||
use crate::config::watch_config;
|
||
use crate::ptp::start_ptp_client;
|
||
use crate::serial_input::start_serial_thread;
|
||
use crate::sync_logic::LtcState;
|
||
use crate::ui::start_ui;
|
||
|
||
use std::{
|
||
fs,
|
||
path::Path,
|
||
sync::{mpsc, Arc, Mutex},
|
||
thread,
|
||
};
|
||
|
||
/// Embed the default config.json at compile time.
|
||
const DEFAULT_CONFIG: &str = include_str!("../config.json");
|
||
|
||
/// If no `config.json` exists alongside the binary, write out the default.
|
||
fn ensure_config() {
|
||
let p = Path::new("config.json");
|
||
if !p.exists() {
|
||
fs::write(p, DEFAULT_CONFIG)
|
||
.expect("Failed to write default config.json");
|
||
eprintln!("⚙️ Emitted default config.json");
|
||
}
|
||
}
|
||
|
||
#[tokio::main]
|
||
async fn main() {
|
||
// 🔄 Ensure there's always a config.json present
|
||
ensure_config();
|
||
env_logger::init();
|
||
|
||
// 1️⃣ Start watching config.json for changes
|
||
let config_arc = watch_config("config.json");
|
||
println!("🔧 Watching config.json...");
|
||
|
||
// 2️⃣ Channel for raw LTC frames
|
||
let (tx, rx) = mpsc::channel();
|
||
println!("✅ Channel created");
|
||
|
||
// 3️⃣ Shared state for UI and serial reader
|
||
let ltc_state = Arc::new(Mutex::new(LtcState::new()));
|
||
println!("✅ State initialised");
|
||
|
||
// 4️⃣ Spawn the serial reader thread (no offset here)
|
||
{
|
||
let tx_clone = tx.clone();
|
||
let state_clone = ltc_state.clone();
|
||
thread::spawn(move || {
|
||
println!("🚀 Serial thread launched");
|
||
start_serial_thread(
|
||
"/dev/ttyACM0",
|
||
115200,
|
||
tx_clone,
|
||
state_clone,
|
||
0, // ignored in serial path
|
||
);
|
||
});
|
||
}
|
||
|
||
// 5️⃣ Spawn PTP client thread (blocking, not async)
|
||
{
|
||
let ptp_state = ltc_state.clone();
|
||
let config_clone = config_arc.clone();
|
||
thread::spawn(move || {
|
||
println!("🚀 PTP thread launched");
|
||
// Create a new tokio runtime for this thread
|
||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||
rt.block_on(start_ptp_client(ptp_state, config_clone));
|
||
});
|
||
}
|
||
|
||
// 6️⃣ Spawn the UI renderer thread, passing the live config Arc
|
||
{
|
||
let ui_state = ltc_state.clone();
|
||
let config_clone = config_arc.clone();
|
||
let port = "/dev/ttyACM0".to_string();
|
||
thread::spawn(move || {
|
||
println!("🖥️ UI thread launched");
|
||
start_ui(ui_state, port, config_clone);
|
||
});
|
||
}
|
||
|
||
// 7️⃣ Keep main thread alive for LTC frames
|
||
println!("📡 Main thread entering LTC frame loop...");
|
||
for _frame in rx {
|
||
// no-op
|
||
}
|
||
}
|