read-ram endpoint
This commit is contained in:
parent
c3469e5259
commit
162d32756c
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -2243,9 +2243,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.4.0"
|
version = "1.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
|
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
@ -2262,7 +2262,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tesla-charge-controller"
|
name = "tesla-charge-controller"
|
||||||
version = "0.1.13"
|
version = "0.1.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
|
@ -2278,6 +2278,7 @@ dependencies = [
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"serialport",
|
"serialport",
|
||||||
|
"termcolor",
|
||||||
"teslatte",
|
"teslatte",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tesla-charge-controller"
|
name = "tesla-charge-controller"
|
||||||
version = "0.1.13"
|
version = "0.1.14"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MITNFA"
|
license = "MITNFA"
|
||||||
description = "Controls Tesla charge rate based on solar charge data"
|
description = "Controls Tesla charge rate based on solar charge data"
|
||||||
|
@ -30,3 +30,4 @@ prometheus = "0.13"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serialport = "4.3"
|
serialport = "4.3"
|
||||||
|
termcolor = "1.4.1"
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -57,12 +57,15 @@ async fn main() {
|
||||||
ron::from_str(&std::fs::read_to_string(&config_path).unwrap()).unwrap();
|
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
|
// 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 {
|
let server_handle = server::launch_server(server::ServerState {
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
state: interface.state.clone(),
|
state: interface.state.clone(),
|
||||||
api_requests,
|
api_requests,
|
||||||
|
pli_requests,
|
||||||
});
|
});
|
||||||
|
|
||||||
// spawn the api loop
|
// spawn the api loop
|
||||||
|
@ -72,7 +75,7 @@ async fn main() {
|
||||||
// await either the next interval OR a message from the other thread
|
// await either the next interval OR a message from the other thread
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = interval.tick() => interface.refresh().await,
|
_ = interval.tick() => interface.refresh().await,
|
||||||
message = receiver.recv() => match message {
|
message = api_receiver.recv() => match message {
|
||||||
Ok(message) => interface.process_request(message).await,
|
Ok(message) => interface.process_request(message).await,
|
||||||
Err(e) => error!("Error on receive channel: {e:#?}")
|
Err(e) => error!("Error on receive channel: {e:#?}")
|
||||||
}
|
}
|
||||||
|
@ -87,8 +90,13 @@ async fn main() {
|
||||||
let mut interval =
|
let mut interval =
|
||||||
tokio::time::interval(std::time::Duration::from_secs(30));
|
tokio::time::interval(std::time::Duration::from_secs(30));
|
||||||
loop {
|
loop {
|
||||||
interval.tick().await;
|
tokio::select! {
|
||||||
pli.refresh();
|
_ = interval.tick() => pli.refresh(),
|
||||||
|
message = pli_receiver.recv() => match message {
|
||||||
|
Ok(message) => pli.process_request(message),
|
||||||
|
Err(e) => error!("Error on receive channel: {e:#?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use std::time::Duration;
|
use std::{io::Write, time::Duration};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use metrics::{describe_gauge, gauge, Gauge};
|
use metrics::{describe_gauge, gauge, Gauge};
|
||||||
use serialport::SerialPort;
|
use serialport::SerialPort;
|
||||||
|
use termcolor::WriteColor;
|
||||||
|
|
||||||
pub struct Pli {
|
pub struct Pli {
|
||||||
port: Box<dyn SerialPort>,
|
port: Box<dyn SerialPort>,
|
||||||
|
@ -12,6 +13,11 @@ pub struct Pli {
|
||||||
internal_load_current: Gauge,
|
internal_load_current: Gauge,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum PliRequest {
|
||||||
|
ReadRam(u8),
|
||||||
|
}
|
||||||
|
|
||||||
impl Pli {
|
impl Pli {
|
||||||
pub fn new(serial_port: String, baud_rate: u32) -> anyhow::Result<Self> {
|
pub fn new(serial_port: String, baud_rate: u32) -> anyhow::Result<Self> {
|
||||||
let port = serialport::new(serial_port, baud_rate)
|
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]) {
|
fn send_command(&mut self, req: [u8; 4]) {
|
||||||
self.port
|
self.port
|
||||||
.write_all(&req)
|
.write_all(&req)
|
||||||
|
@ -68,7 +94,10 @@ impl Pli {
|
||||||
buf
|
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));
|
self.send_command(command(20, address.into(), 0));
|
||||||
let buf: [u8; 2] = self.receive();
|
let buf: [u8; 2] = self.receive();
|
||||||
if buf[0] == 200 { Some(buf[1]) } else { None }
|
if buf[0] == 200 { Some(buf[1]) } else { None }
|
||||||
|
|
|
@ -11,6 +11,7 @@ use rocket::{
|
||||||
use crate::{
|
use crate::{
|
||||||
api_interface::InterfaceRequest,
|
api_interface::InterfaceRequest,
|
||||||
config::Config,
|
config::Config,
|
||||||
|
pl_interface::PliRequest,
|
||||||
types::{CarState, ChargeState, ClimateState},
|
types::{CarState, ChargeState, ClimateState},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ pub struct ServerState {
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
pub state: Arc<RwLock<CarState>>,
|
pub state: Arc<RwLock<CarState>>,
|
||||||
pub api_requests: Sender<InterfaceRequest>,
|
pub api_requests: Sender<InterfaceRequest>,
|
||||||
|
pub pli_requests: Sender<PliRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn launch_server(state: ServerState) {
|
pub async fn launch_server(state: ServerState) {
|
||||||
|
@ -47,7 +49,7 @@ fn rocket(state: ServerState) -> rocket::Rocket<rocket::Build> {
|
||||||
.mount("/", fileserver)
|
.mount("/", fileserver)
|
||||||
.mount(
|
.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()
|
.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;
|
pub struct Cors;
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
|
|
Loading…
Reference in a new issue