read-ram endpoint

This commit is contained in:
Alex Janka 2024-01-11 08:57:41 +11:00
parent c3469e5259
commit 162d32756c
5 changed files with 58 additions and 11 deletions

7
Cargo.lock generated
View file

@ -2243,9 +2243,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
@ -2262,7 +2262,7 @@ dependencies = [
[[package]]
name = "tesla-charge-controller"
version = "0.1.13"
version = "0.1.14"
dependencies = [
"anyhow",
"async-channel",
@ -2278,6 +2278,7 @@ dependencies = [
"ron",
"serde",
"serialport",
"termcolor",
"teslatte",
"thiserror",
"tokio",

View file

@ -1,6 +1,6 @@
[package]
name = "tesla-charge-controller"
version = "0.1.13"
version = "0.1.14"
edition = "2021"
license = "MITNFA"
description = "Controls Tesla charge rate based on solar charge data"
@ -30,3 +30,4 @@ prometheus = "0.13"
env_logger = "0.10"
log = "0.4"
serialport = "4.3"
termcolor = "1.4.1"

View file

@ -57,12 +57,15 @@ async fn main() {
ron::from_str(&std::fs::read_to_string(&config_path).unwrap()).unwrap();
// build the channel that takes messages from the webserver thread to the api thread
let (api_requests, receiver) = async_channel::unbounded();
let (api_requests, api_receiver) = async_channel::unbounded();
// and to the pli thread
let (pli_requests, pli_receiver) = async_channel::unbounded();
let server_handle = server::launch_server(server::ServerState {
config: config.clone(),
state: interface.state.clone(),
api_requests,
pli_requests,
});
// spawn the api loop
@ -72,7 +75,7 @@ async fn main() {
// await either the next interval OR a message from the other thread
tokio::select! {
_ = interval.tick() => interface.refresh().await,
message = receiver.recv() => match message {
message = api_receiver.recv() => match message {
Ok(message) => interface.process_request(message).await,
Err(e) => error!("Error on receive channel: {e:#?}")
}
@ -87,8 +90,13 @@ async fn main() {
let mut interval =
tokio::time::interval(std::time::Duration::from_secs(30));
loop {
interval.tick().await;
pli.refresh();
tokio::select! {
_ = interval.tick() => pli.refresh(),
message = pli_receiver.recv() => match message {
Ok(message) => pli.process_request(message),
Err(e) => error!("Error on receive channel: {e:#?}")
}
}
}
});
}

View file

@ -1,8 +1,9 @@
use std::time::Duration;
use std::{io::Write, time::Duration};
use anyhow::Context;
use metrics::{describe_gauge, gauge, Gauge};
use serialport::SerialPort;
use termcolor::WriteColor;
pub struct Pli {
port: Box<dyn SerialPort>,
@ -12,6 +13,11 @@ pub struct Pli {
internal_load_current: Gauge,
}
#[derive(Debug, Clone, Copy)]
pub enum PliRequest {
ReadRam(u8),
}
impl Pli {
pub fn new(serial_port: String, baud_rate: u32) -> anyhow::Result<Self> {
let port = serialport::new(serial_port, baud_rate)
@ -53,6 +59,26 @@ impl Pli {
}
}
pub fn process_request(&mut self, message: PliRequest) {
match message {
PliRequest::ReadRam(address) => match self.read_ram(address) {
Ok(data) => {
let mut stdout =
termcolor::StandardStream::stdout(termcolor::ColorChoice::Always);
let _ = stdout.set_color(
termcolor::ColorSpec::new().set_fg(Some(termcolor::Color::Green)),
);
if writeln!(&mut stdout, "Read RAM at {address}: data {data}").is_err() {
log::warn!(
"Failed to set stdout colour\nRead RAM at {address}: data {data}"
);
};
}
Err(e) => log::error!("RAM read error: {e:?}"),
},
}
}
fn send_command(&mut self, req: [u8; 4]) {
self.port
.write_all(&req)
@ -68,7 +94,10 @@ impl Pli {
buf
}
fn read_ram(&mut self, address: PlRamAddress) -> anyhow::Result<u8> {
fn read_ram<T>(&mut self, address: T) -> anyhow::Result<u8>
where
T: Into<u8>,
{
self.send_command(command(20, address.into(), 0));
let buf: [u8; 2] = self.receive();
if buf[0] == 200 { Some(buf[1]) } else { None }

View file

@ -11,6 +11,7 @@ use rocket::{
use crate::{
api_interface::InterfaceRequest,
config::Config,
pl_interface::PliRequest,
types::{CarState, ChargeState, ClimateState},
};
@ -22,6 +23,7 @@ pub struct ServerState {
pub config: Config,
pub state: Arc<RwLock<CarState>>,
pub api_requests: Sender<InterfaceRequest>,
pub pli_requests: Sender<PliRequest>,
}
pub async fn launch_server(state: ServerState) {
@ -47,7 +49,7 @@ fn rocket(state: ServerState) -> rocket::Rocket<rocket::Build> {
.mount("/", fileserver)
.mount(
"/",
routes![home, charge_state, flash, climate_state, metrics],
routes![home, charge_state, flash, climate_state, metrics, read_ram],
)
}
@ -79,6 +81,12 @@ fn metrics() -> Option<String> {
.ok()
}
#[get("/read-ram/<address>")]
async fn read_ram(address: u8, state: &State<ServerState>) -> String {
let _ = state.pli_requests.send(PliRequest::ReadRam(address)).await;
format!("reading at ram address {address}")
}
pub struct Cors;
#[rocket::async_trait]