Refactor SD LED functionality even more; move to different project and expand scope

This commit is contained in:
NGnius (Graham) 2023-12-29 00:34:02 -05:00
parent 508c6ceb9e
commit 437f5beb71
9 changed files with 409 additions and 621 deletions

729
backend/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -29,8 +29,8 @@ simplelog = "0.12"
# limits & driver functionality # limits & driver functionality
limits_core = { version = "3", path = "./limits_core" } limits_core = { version = "3", path = "./limits_core" }
regex = "1" regex = "1"
libryzenadj = { version = "0.12" } smokepatio = { version = "*", path = "../../smokepatio" }
sd_led = { version = "*", path = "./sd_led" } libryzenadj = { version = "0.14", path = "../../libryzenadj-rs-14" }
# ureq's tls feature does not like musl targets # ureq's tls feature does not like musl targets
ureq = { version = "2", features = ["json", "gzip", "brotli", "charset"], default-features = false, optional = true } ureq = { version = "2", features = ["json", "gzip", "brotli", "charset"], default-features = false, optional = true }

View file

@ -1,16 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "sd_led"
version = "0.1.0"
dependencies = [
"log",
]

View file

@ -1,10 +0,0 @@
[package]
name = "sd_led"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# logging
log = "0.4"

View file

@ -1,193 +0,0 @@
//! Rough Rust port of some BatCtrl functionality
//! Original: /usr/share/jupiter_controller_fw_updater/RA_bootloader_updater/linux_host_tools/BatCtrl
//! I do not have access to the source code, so this is my own interpretation of what it does.
//!
//! But also Quanta is based in a place with some questionable copyright practices, so...
pub mod raw_io;
use std::io::Error;
pub fn set_led(red_unused: bool, green_aka_white: bool, blue_unused: bool) -> Result<usize, Error> {
let payload: u8 = 0x80
| (red_unused as u8 & 1)
| ((green_aka_white as u8 & 1) << 1)
| ((blue_unused as u8 & 1) << 2);
//log::info!("Payload: {:b}", payload);
raw_io::write2(Setting::LEDStatus as _, payload)
}
pub fn set(setting: Setting, mode: u8) -> Result<usize, Error> {
raw_io::write2(setting as u8, mode)
}
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum Setting {
CycleCount = 0x32,
ControlBoard = 0x6C,
Charge = 0xA6,
ChargeMode = 0x76,
LEDStatus = 199,
LEDBreathing = 0x63,
FanSpeed = 0x2c, // lower 3 bits seem to not do everything, every other bit increases speed -- 5 total steps, 0xf4 seems to do something similar too
// 0x40 write 0x08 makes LED red + green turn on
// 0x58 write 0x80 shuts off battery power (bms?)
// 0x63 makes blue (0x02) or white (0x01) LED breathing effect
// 0x7a write 0x01, 0x02, or 0x03 turns off display
}
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum ControlBoard {
Enable = 0xAA,
Disable = 0xAB,
}
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum ChargeMode {
Normal = 0,
Discharge = 0x42,
Idle = 0x45,
}
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum Charge {
Enable = 0,
Disable = 4,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[allow(dead_code)]
fn led_all_experiment_test() -> Result<(), Error> {
let original = raw_io::write_read(Setting::LEDStatus as _)?;
let sleep_dur = std::time::Duration::from_millis(1000);
for b in 0..0x7F {
let actual = 0x80 | b;
raw_io::write2(Setting::LEDStatus as _, actual)?;
println!("Wrote {actual:#b} to LED byte");
std::thread::sleep(sleep_dur);
}
raw_io::write2(Setting::LEDStatus as _, original)?;
Ok(())
}
#[test]
#[allow(dead_code)]
fn led_singles_experiment_test() -> Result<(), Error> {
let original = raw_io::write_read(Setting::LEDStatus as _)?;
let sleep_dur = std::time::Duration::from_millis(1000);
let mut value = 1;
for _ in 0..std::mem::size_of::<u8>()*8 {
let actual = 0x80 | value;
raw_io::write2(Setting::LEDStatus as _, actual)?;
println!("Wrote {actual:#b} to LED byte");
value = value << 1;
std::thread::sleep(sleep_dur);
}
raw_io::write2(Setting::LEDStatus as _, original)?;
Ok(())
}
#[test]
#[allow(dead_code)]
fn led_specify_experiment_test() -> Result<(), Error> {
let mut buffer = String::new();
println!("LED number(s) to display?");
std::io::stdin().read_line(&mut buffer)?;
let mut resultant = 0;
let original = raw_io::write_read(Setting::LEDStatus as _)?;
for word in buffer.split(' ') {
let trimmed_word = word.trim();
if !trimmed_word.is_empty() {
let value: u8 = trimmed_word.parse().expect("Invalid u8 number");
let actual = 0x80 | value;
raw_io::wait_ready_for_write()?;
raw_io::write2(Setting::LEDStatus as _, actual)?;
println!("Wrote {actual:#b} to LED byte");
resultant |= actual;
}
}
println!("Effectively wrote {resultant:#b} to LED byte");
println!("Press enter to return to normal");
std::io::stdin().read_line(&mut buffer)?;
raw_io::write2(Setting::LEDStatus as _, original)?;
Ok(())
}
#[test]
#[allow(dead_code)]
fn breath_specify_experiment_test() -> Result<(), Error> {
let mut buffer = String::new();
println!("LED number(s) to display?");
std::io::stdin().read_line(&mut buffer)?;
for word in buffer.split(' ') {
let trimmed_word = word.trim();
if !trimmed_word.is_empty() {
let value: u8 = trimmed_word.parse().expect("Invalid u8 number");
let actual = 0x20 | value;
raw_io::wait_ready_for_write()?;
raw_io::write2(0x63, actual)?;
println!("Wrote {actual:#b} to LED breathing byte");
}
}
println!("Press enter to return to normal");
std::io::stdin().read_line(&mut buffer)?;
raw_io::write2(0x63, 0)?;
Ok(())
}
#[test]
#[allow(dead_code)]
fn unmapped_ports_experiment_test() -> Result<(), Error> {
let sleep_dur = std::time::Duration::from_millis(10000);
let value = 0xaa;
for addr in 0x63..0x64 {
//raw_io::wait_ready_for_read()?;
//let read = raw_io::write_read(addr)?;
raw_io::wait_ready_for_write()?;
raw_io::write2(addr, value)?;
println!("wrote {value:#b} for {addr:#x} port");
std::thread::sleep(sleep_dur);
}
//raw_io::write2(Setting::LEDStatus as _, 0)?;
Ok(())
}
#[test]
#[allow(dead_code)]
fn write_specify_experiment_test() -> Result<(), Error> {
let mut buffer = String::new();
println!("Register?");
std::io::stdin().read_line(&mut buffer)?;
let register: u8 = buffer.trim().parse().expect("Invalid u8 number");
buffer.clear();
println!("Value(s)?");
std::io::stdin().read_line(&mut buffer)?;
for word in buffer.split(' ') {
let trimmed_word = word.trim();
if !trimmed_word.is_empty() {
let value: u8 = trimmed_word.parse().expect("Invalid u8 number");
raw_io::wait_ready_for_write()?;
raw_io::write2(register, value)?;
println!("Wrote {value:#09b} to {register:#02x} register");
}
}
println!("Press enter to clear register");
std::io::stdin().read_line(&mut buffer)?;
raw_io::write2(register, 0)?;
Ok(())
}
}

View file

@ -1,51 +0,0 @@
use std::fs::OpenOptions;
use std::io::{Error, Read, Seek, SeekFrom, Write};
#[inline]
pub fn write2(p0: u8, p1: u8) -> Result<usize, Error> {
write_to(0x6c, 0x81)?;
wait_ready_for_write()?;
let count0 = write_to(0x68, p0)?;
wait_ready_for_write()?;
let count1 = write_to(0x68, p1)?;
Ok(count0 + count1)
}
#[inline]
pub fn write_read(p0: u8) -> Result<u8, Error> {
write_to(0x6c, 0x81)?;
wait_ready_for_write()?;
write_to(0x68, p0)?;
wait_ready_for_read()?;
read_from(0x68)
}
pub fn write_to(location: u64, value: u8) -> Result<usize, Error> {
let mut file = OpenOptions::new().write(true).open("/dev/port")?;
file.seek(SeekFrom::Start(location))?;
file.write(&[value])
}
pub fn read_from(location: u64) -> Result<u8, Error> {
let mut file = OpenOptions::new().read(true).open("/dev/port")?;
file.seek(SeekFrom::Start(location))?;
let mut buffer = [0];
file.read(&mut buffer)?;
Ok(buffer[0])
}
pub fn wait_ready_for_write() -> Result<(), Error> {
let mut count = 0;
while count < 0x1ffff && (read_from(0x6c)? & 2) != 0 {
count += 1;
}
Ok(())
}
pub fn wait_ready_for_read() -> Result<(), Error> {
let mut count = 0;
while count < 0x1ffff && (read_from(0x6c)? & 1) == 0 {
count += 1;
}
Ok(())
}

View file

@ -6,7 +6,7 @@ use sysfuss::capability::attributes;
use limits_core::json_v2::GenericBatteryLimit; use limits_core::json_v2::GenericBatteryLimit;
use sd_led::ChargeMode; use smokepatio::ec::ChargeMode;
use crate::api::RangeLimit; use crate::api::RangeLimit;
use crate::persist::{BatteryEventJson, BatteryJson}; use crate::persist::{BatteryEventJson, BatteryJson};
use crate::settings::{TBattery, ProviderBuilder}; use crate::settings::{TBattery, ProviderBuilder};
@ -131,7 +131,7 @@ impl EventInstruction {
fn set_charge_mode(&self) -> Result<(), SettingError> { fn set_charge_mode(&self) -> Result<(), SettingError> {
if let Some(charge_mode) = self.charge_mode { if let Some(charge_mode) = self.charge_mode {
sd_led::set(sd_led::Setting::ChargeMode, charge_mode as _) smokepatio::ec::set(smokepatio::ec::Setting::ChargeMode, charge_mode as _)
.map_err(|e| SettingError { .map_err(|e| SettingError {
msg: format!("Failed to set charge mode: {}", e), msg: format!("Failed to set charge mode: {}", e),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,
@ -329,7 +329,7 @@ impl Battery {
fn set_charge_mode(&mut self) -> Result<(), SettingError> { fn set_charge_mode(&mut self) -> Result<(), SettingError> {
if let Some(charge_mode) = self.charge_mode { if let Some(charge_mode) = self.charge_mode {
self.state.charge_mode_set = true; self.state.charge_mode_set = true;
sd_led::set(sd_led::Setting::ChargeMode, charge_mode as _) smokepatio::ec::set(smokepatio::ec::Setting::ChargeMode, charge_mode as _)
.map_err(|e| SettingError { .map_err(|e| SettingError {
msg: format!("Failed to set charge mode: {}", e), msg: format!("Failed to set charge mode: {}", e),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,
@ -337,7 +337,7 @@ impl Battery {
.map(|_| ()) .map(|_| ())
} else if self.state.charge_mode_set { } else if self.state.charge_mode_set {
self.state.charge_mode_set = false; self.state.charge_mode_set = false;
sd_led::set(sd_led::Setting::ChargeMode, ChargeMode::Normal as _) smokepatio::ec::set(smokepatio::ec::Setting::ChargeMode, ChargeMode::Normal as _)
.map_err(|e| SettingError { .map_err(|e| SettingError {
msg: format!("Failed to set charge mode: {}", e), msg: format!("Failed to set charge mode: {}", e),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,

View file

@ -27,20 +27,15 @@ const THINGS: &[u8] = &[
const TIME_UNIT: std::time::Duration = std::time::Duration::from_millis(200); const TIME_UNIT: std::time::Duration = std::time::Duration::from_millis(200);
pub fn flash_led() { pub fn flash_led() {
let led_status = sd_led::Setting::LEDStatus;
let old_led_state = sd_led::raw_io::write_read(led_status as _)
.map_err(|e| log::error!("Failed to read LED status: {}", e));
for &code in THINGS { for &code in THINGS {
let on = code != 0; let on = code != 0;
if let Err(e) = sd_led::set_led(on, on, false) { if let Err(e) = smokepatio::ec::led::constant::set(if on { smokepatio::ec::led::constant::Colour::White } else { smokepatio::ec::led::constant::Colour::Off }) {
log::error!("Thing err: {}", e); log::error!("Thing err: {}", e);
} }
std::thread::sleep(TIME_UNIT); std::thread::sleep(TIME_UNIT);
} }
if let Ok(old_led_state) = old_led_state { log::debug!("Restoring LED state");
log::debug!("Restoring LED state to {:#02b}", old_led_state); smokepatio::ec::led::constant::set(smokepatio::ec::led::constant::Colour::Off)
sd_led::raw_io::write2(led_status as _, old_led_state)
.map_err(|e| log::error!("Failed to restore LED status: {}", e)) .map_err(|e| log::error!("Failed to restore LED status: {}", e))
.unwrap(); .unwrap();
}
} }

View file

@ -17,9 +17,9 @@ class Plugin:
env_proc["LD_LIBRARY_PATH"] += ":"+PARENT_DIR+"/bin" env_proc["LD_LIBRARY_PATH"] += ":"+PARENT_DIR+"/bin"
else: else:
env_proc["LD_LIBRARY_PATH"] = ":"+PARENT_DIR+"/bin" env_proc["LD_LIBRARY_PATH"] = ":"+PARENT_DIR+"/bin"
self.backend_proc = subprocess.Popen( '''self.backend_proc = subprocess.Popen(
[PARENT_DIR + "/bin/backend"], [PARENT_DIR + "/bin/backend"],
env = env_proc) env = env_proc)'''
while True: while True:
await asyncio.sleep(1) await asyncio.sleep(1)