From bda2d63e994ed815b7479ab827cbdb18d4850589 Mon Sep 17 00:00:00 2001 From: Alex Janka <alex@alexjanka.com> Date: Sat, 28 Dec 2024 22:39:15 +1100 Subject: [PATCH] pl: async serial --- Cargo.lock | 1 - charge-controller-supervisor/Cargo.toml | 1 - .../src/controller.rs | 2 +- charge-controller-supervisor/src/pl.rs | 87 +++++++++---------- 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e889205..48b01bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,7 +252,6 @@ dependencies = [ "rocket", "serde", "serde_json", - "serialport", "tokio", "tokio-modbus", "tokio-serial", diff --git a/charge-controller-supervisor/Cargo.toml b/charge-controller-supervisor/Cargo.toml index a5bebc2..f56b4a1 100644 --- a/charge-controller-supervisor/Cargo.toml +++ b/charge-controller-supervisor/Cargo.toml @@ -21,7 +21,6 @@ chrono = "0.4.39" prometheus = "0.13.4" env_logger = "0.11.6" log = "0.4.22" -serialport = "4.6.1" futures = "0.3.31" tokio-modbus = "0.16.1" tokio-serial = "5.4.4" diff --git a/charge-controller-supervisor/src/controller.rs b/charge-controller-supervisor/src/controller.rs index 5df03a5..6932d71 100644 --- a/charge-controller-supervisor/src/controller.rs +++ b/charge-controller-supervisor/src/controller.rs @@ -69,7 +69,7 @@ impl ControllerInner { pub async fn refresh(&mut self) -> eyre::Result<CommonData> { match self { ControllerInner::Pl(pli) => { - let pl_data = pli.refresh()?; + let pl_data = pli.refresh().await?; Ok(pl_data) } ControllerInner::Tristar(tristar) => { diff --git a/charge-controller-supervisor/src/pl.rs b/charge-controller-supervisor/src/pl.rs index f684d9b..e36689c 100644 --- a/charge-controller-supervisor/src/pl.rs +++ b/charge-controller-supervisor/src/pl.rs @@ -1,8 +1,7 @@ -use std::{io::Write, time::Duration}; - use chrono::Timelike; use serde::{Deserialize, Serialize}; -use serialport::SerialPort; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio_serial::{SerialPort, SerialPortBuilderExt}; use crate::gauges::{ BATTERY_TEMP, BATTERY_VOLTAGE, CHARGE_STATE, INPUT_CURRENT, PL_DUTY_CYCLE, PL_LOAD_CURRENT, @@ -11,7 +10,7 @@ use crate::gauges::{ pub struct Pli { friendly_name: String, - port: Box<dyn SerialPort>, + port: tokio_serial::SerialStream, } #[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)] @@ -111,10 +110,10 @@ impl Pli { friendly_name: &str, baud_rate: u32, timeout: u64, - ) -> Result<Self, serialport::Error> { - let port = serialport::new(serial_port, baud_rate) - .timeout(Duration::from_millis(timeout)) - .open()?; + ) -> Result<Self, tokio_serial::Error> { + let port = tokio_serial::new(serial_port, baud_rate) + .timeout(std::time::Duration::from_millis(timeout)) + .open_native_async()?; Ok(Self { friendly_name: friendly_name.to_owned(), @@ -122,8 +121,8 @@ impl Pli { }) } - pub fn refresh(&mut self) -> eyre::Result<crate::controller::CommonData> { - let new_state = self.read_state()?; + pub async fn refresh(&mut self) -> eyre::Result<crate::controller::CommonData> { + let new_state = self.read_state().await?; BATTERY_VOLTAGE .with_label_values(&[&self.friendly_name]) .set(new_state.battery_voltage); @@ -153,14 +152,14 @@ impl Pli { } #[expect(dead_code, reason = "writing settings is not yet implemented")] - pub fn process_request(&mut self, message: PliRequest) -> eyre::Result<()> { + pub async fn process_request(&mut self, message: PliRequest) -> eyre::Result<()> { match message { PliRequest::ReadRam(address) => { - let data = self.read_ram(address)?; + let data = self.read_ram(address).await?; log::warn!("Read RAM at {address}: data {data}"); } PliRequest::ReadEeprom(address) => { - let data = self.read_eeprom(address)?; + let data = self.read_eeprom(address).await?; log::warn!("Read EEPROM at {address}: data {data}"); } PliRequest::SyncTime => { @@ -168,85 +167,81 @@ impl Pli { let timestamp = (((now.hour() * 10) + (now.minute() / 6)) & 0xFF) as u8; let min = (now.minute() % 6) as u8; let sec = (now.second() / 2).min(29) as u8; - self.write_ram(PlRamAddress::Hour, timestamp)?; - self.write_ram(PlRamAddress::Min, min)?; - self.write_ram(PlRamAddress::Sec, sec)?; + self.write_ram(PlRamAddress::Hour, timestamp).await?; + self.write_ram(PlRamAddress::Min, min).await?; + self.write_ram(PlRamAddress::Sec, sec).await?; log::warn!( "Set time: {now} corresponds to {timestamp} + minutes {min} + seconds {sec}" ); } PliRequest::SetRegulatorState(state) => { log::warn!("Setting regulator state to {state:?}"); - self.write_ram(PlRamAddress::Rstate, state.into())?; + self.write_ram(PlRamAddress::Rstate, state.into()).await?; } } Ok(()) } - fn read_state(&mut self) -> eyre::Result<PlState> { + async fn read_state(&mut self) -> eyre::Result<PlState> { Ok(PlState { - battery_voltage: f64::from(self.read_ram(PlRamAddress::Batv)?) * (4. / 10.), - target_voltage: f64::from(self.read_ram(PlRamAddress::Vreg)?) * (4. / 10.), - duty_cycle: f64::from(self.read_ram(PlRamAddress::Dutycyc)?) / 255., - internal_charge_current: f64::from(self.read_ram(PlRamAddress::Cint)?) * (4. / 10.), - internal_load_current: f64::from(self.read_ram(PlRamAddress::Lint)?) * (4. / 10.), - battery_temp: f64::from(self.read_ram(PlRamAddress::Battemp)?), - regulator_state: self.read_ram(PlRamAddress::Rstate)?.into(), + battery_voltage: f64::from(self.read_ram(PlRamAddress::Batv).await?) * (4. / 10.), + target_voltage: f64::from(self.read_ram(PlRamAddress::Vreg).await?) * (4. / 10.), + duty_cycle: f64::from(self.read_ram(PlRamAddress::Dutycyc).await?) / 255., + internal_charge_current: f64::from(self.read_ram(PlRamAddress::Cint).await?) + * (4. / 10.), + internal_load_current: f64::from(self.read_ram(PlRamAddress::Lint).await?) * (4. / 10.), + battery_temp: f64::from(self.read_ram(PlRamAddress::Battemp).await?), + regulator_state: self.read_ram(PlRamAddress::Rstate).await?.into(), }) } - fn send_command(&mut self, req: [u8; 4]) -> eyre::Result<()> { + async fn send_command(&mut self, req: [u8; 4]) -> eyre::Result<()> { self.flush()?; - self.port.write_all(&req)?; + self.port.write_all(&req).await?; Ok(()) } fn flush(&mut self) -> eyre::Result<()> { - self.port.flush()?; - while let Ok(num) = self.port.bytes_to_read() { - if num == 0 { - return Ok(()); - } - let _ = self.port.read(&mut [0; 8]); - } + self.port.clear(tokio_serial::ClearBuffer::All)?; Ok(()) } - fn receive<const LENGTH: usize>(&mut self) -> eyre::Result<[u8; LENGTH]> { + async fn receive<const LENGTH: usize>(&mut self) -> eyre::Result<[u8; LENGTH]> { let mut buf = [0; LENGTH]; - self.port.read_exact(&mut buf)?; + self.port.read_exact(&mut buf).await?; Ok(buf) } - fn read_ram<T>(&mut self, address: T) -> eyre::Result<u8> + async fn read_ram<T>(&mut self, address: T) -> eyre::Result<u8> where T: Into<u8>, { - self.send_command(command(20, address.into(), 0))?; - let buf = self.receive::<1>()?; + self.send_command(command(20, address.into(), 0)).await?; + let buf = self.receive::<1>().await?; if buf[0] == 200 { - Ok(self.receive::<1>()?[0]) + Ok(self.receive::<1>().await?[0]) } else { Err(eyre::eyre!("read error: result is {}", buf[0])) } } - fn write_ram<T>(&mut self, address: T, data: u8) -> eyre::Result<()> + async fn write_ram<T>(&mut self, address: T, data: u8) -> eyre::Result<()> where T: Into<u8>, { - self.send_command(command(152, address.into(), data))?; + self.send_command(command(152, address.into(), data)) + .await?; Ok(()) } - fn read_eeprom<T>(&mut self, address: T) -> eyre::Result<u8> + async fn read_eeprom<T>(&mut self, address: T) -> eyre::Result<u8> where T: Into<u8>, { - self.send_command(command(72, address.into(), 0))?; - let buf = self.receive::<1>()?; + self.send_command(command(72, address.into(), 0)).await?; + let buf = self.receive::<1>().await?; if buf[0] == 200 { - Ok(self.receive::<1>()?[0]) + Ok(self.receive::<1>().await?[0]) } else { Err(eyre::eyre!("read error: result is {}", buf[0])) }