Implement flag file for optimistic cold boot state

If this is the first time the daemon runs, we assume 99C (just under the
limit, which means no reduction). Otherwise, we assume the max
temperature, and therefore max limit.

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2023-10-13 13:30:11 +09:00
parent 910124421b
commit ffa5af391d
2 changed files with 44 additions and 11 deletions

View file

@ -7,9 +7,9 @@
we gracefully bail and use an IOCTL to shut off the speakers. we gracefully bail and use an IOCTL to shut off the speakers.
*/ */
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fs::read_to_string; use std::fs;
use std::io; use std::io;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::{thread::sleep, time}; use std::{thread::sleep, time};
@ -29,6 +29,8 @@ const DEFAULT_CONFIG_PATH: &str = "share/speakersafetyd";
const UNLOCK_MAGIC: i32 = 0xdec1be15u32 as i32; const UNLOCK_MAGIC: i32 = 0xdec1be15u32 as i32;
const FLAGFILE: &str = "/run/speakersafetyd.flag";
/// Simple program to greet a person /// Simple program to greet a person
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
@ -117,10 +119,32 @@ fn main() {
info!("Opening control device"); info!("Opening control device");
let ctl: alsa::ctl::Ctl = helpers::open_card(&device); let ctl: alsa::ctl::Ctl = helpers::open_card(&device);
let flag_path = Path::new(FLAGFILE);
let cold_boot = match flag_path.try_exists() {
Ok(true) => {
info!("Startup mode: Warm boot");
false
}
Ok(false) => {
info!("Startup mode: Cold boot");
if fs::write(flag_path, b"started").is_err() {
warn!("Failed to write flag file, continuing as warm boot");
false
} else {
true
}
}
Err(_) => {
warn!("Failed to test flag file, continuing as warm boot");
false
}
};
let mut groups: BTreeMap<usize, SpeakerGroup> = BTreeMap::new(); let mut groups: BTreeMap<usize, SpeakerGroup> = BTreeMap::new();
for i in speaker_names { for i in speaker_names {
let speaker: types::Speaker = types::Speaker::new(&globals, &i, &cfg, &ctl); let speaker: types::Speaker = types::Speaker::new(&globals, &i, &cfg, &ctl, cold_boot);
groups groups
.entry(speaker.group) .entry(speaker.group)
@ -164,8 +188,15 @@ fn main() {
unlock_elem.write_int(&ctl, UNLOCK_MAGIC); unlock_elem.write_int(&ctl, UNLOCK_MAGIC);
for (idx, group) in groups.iter_mut() { for (idx, group) in groups.iter_mut() {
if cold_boot {
// Preset the gains to no reduction on cold boot
group.speakers.iter_mut().for_each(|s| s.update(&ctl, 0.0)); group.speakers.iter_mut().for_each(|s| s.update(&ctl, 0.0));
group.gain = 0.0; group.gain = 0.0;
} else {
// Leave the gains at whatever the kernel limit is, use anything
// random for group.gain so the gains will update on the first cycle.
group.gain = -999.0;
}
} }
let mut last_update = Instant::now(); let mut last_update = Instant::now();

View file

@ -227,7 +227,7 @@ pub struct Speaker {
} }
impl Speaker { impl Speaker {
pub fn new(globals: &Globals, name: &str, config: &Ini, ctl: &Ctl) -> Speaker { pub fn new(globals: &Globals, name: &str, config: &Ini, ctl: &Ctl, cold_boot: bool) -> Speaker {
info!("Speaker [{}]:", name); info!("Speaker [{}]:", name);
let section = "Speaker/".to_owned() + name; let section = "Speaker/".to_owned() + name;
@ -252,15 +252,17 @@ impl Speaker {
let s = &mut new_speaker.s; let s = &mut new_speaker.s;
s.t_coil = if cold_boot {
// Assume warm but not warm enough to limit
globals.t_safe_max as f64 - 1f64
} else {
// Worst case startup assumption // Worst case startup assumption
s.t_coil = (new_speaker.t_limit - new_speaker.t_headroom) as f64; (new_speaker.t_limit - new_speaker.t_headroom) as f64
};
s.t_magnet = globals.t_ambient as f64 s.t_magnet = globals.t_ambient as f64
+ (s.t_coil - globals.t_ambient as f64) + (s.t_coil - globals.t_ambient as f64)
* (new_speaker.tr_magnet / (new_speaker.tr_magnet + new_speaker.tr_coil)) as f64; * (new_speaker.tr_magnet / (new_speaker.tr_magnet + new_speaker.tr_coil)) as f64;
// s.t_coil = globals.t_ambient as f64;
// s.t_magnet = globals.t_ambient as f64;
let max_dt = new_speaker.t_limit - new_speaker.t_headroom - globals.t_ambient; let max_dt = new_speaker.t_limit - new_speaker.t_headroom - globals.t_ambient;
let max_pwr = max_dt / (new_speaker.tr_magnet + new_speaker.tr_coil); let max_pwr = max_dt / (new_speaker.tr_magnet + new_speaker.tr_coil);