pl: async serial

This commit is contained in:
Alex Janka 2024-12-28 22:39:15 +11:00
parent bc0da6be11
commit bda2d63e99
4 changed files with 42 additions and 49 deletions

1
Cargo.lock generated
View file

@ -252,7 +252,6 @@ dependencies = [
"rocket",
"serde",
"serde_json",
"serialport",
"tokio",
"tokio-modbus",
"tokio-serial",

View file

@ -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"

View file

@ -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) => {

View file

@ -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]))
}