make display thread dedicated, move to display.rs
display thread should be dedicated to not steal resources from tokio
This commit is contained in:
parent
07bc399bbc
commit
0e3d324748
37
src/api.rs
37
src/api.rs
|
@ -1,4 +1,4 @@
|
||||||
use crate::display::EInkPanel;
|
use crate::display::{create_display_thread, EInkPanel};
|
||||||
use crate::dither::{DitherMethod, DitheredImage};
|
use crate::dither::{DitherMethod, DitheredImage};
|
||||||
use crate::eink::Palette;
|
use crate::eink::Palette;
|
||||||
use axum::async_trait;
|
use axum::async_trait;
|
||||||
|
@ -10,10 +10,10 @@ use image::{ImageReader, RgbImage};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::mpsc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::sync::mpsc::{self, Receiver, Sender};
|
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
use tracing::{error, info, instrument};
|
use tracing::{error, info, instrument};
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
@ -24,18 +24,17 @@ pub enum ApiError {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
display_channel: Sender<DisplaySetCommand>,
|
display_channel: mpsc::Sender<Box<DitheredImage>>,
|
||||||
display_task: Arc<JoinHandle<()>>,
|
display_task: Arc<JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(disp: Box<dyn EInkPanel + Send>) -> Self {
|
pub fn new(disp: Box<dyn EInkPanel + Send>) -> Self {
|
||||||
let (tx, rx) = mpsc::channel(2);
|
let (handle, tx) = create_display_thread(disp);
|
||||||
let task = tokio::spawn(display_task(rx, disp));
|
|
||||||
Self {
|
Self {
|
||||||
display_channel: tx,
|
display_channel: tx,
|
||||||
display_task: Arc::new(task),
|
display_task: Arc::new(handle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,25 +64,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DisplaySetCommand {
|
|
||||||
img: Box<DitheredImage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
pub async fn display_task(
|
|
||||||
mut rx: Receiver<DisplaySetCommand>,
|
|
||||||
mut display: Box<dyn EInkPanel + Send>,
|
|
||||||
) {
|
|
||||||
while let Some(cmd) = rx.recv().await {
|
|
||||||
info!("Got a display set command");
|
|
||||||
if let Err(e) = display.display(&cmd.img) {
|
|
||||||
error!("Error displaying command {e}");
|
|
||||||
}
|
|
||||||
info!("Done setting display");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// API routes for axum
|
/// API routes for axum
|
||||||
/// Start with the basics: Send an image, crop it, dither, and upload.
|
/// Start with the basics: Send an image, crop it, dither, and upload.
|
||||||
/// we defer the upload to a separate task.
|
/// we defer the upload to a separate task.
|
||||||
|
@ -163,10 +143,7 @@ async fn set_image(
|
||||||
let mut dither = img_req.dither_method.get_ditherer();
|
let mut dither = img_req.dither_method.get_ditherer();
|
||||||
dither.dither(&img_req.image, &mut buf);
|
dither.dither(&img_req.image, &mut buf);
|
||||||
}
|
}
|
||||||
let cmd = DisplaySetCommand { img: Box::new(buf) };
|
ctx.display_channel.send(Box::new(buf))?;
|
||||||
ctx.display_channel
|
|
||||||
.send_timeout(cmd, Duration::from_secs(10))
|
|
||||||
.await?;
|
|
||||||
Ok(StatusCode::OK)
|
Ok(StatusCode::OK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
|
// Manages display hardware
|
||||||
|
use crate::dither::DitheredImage;
|
||||||
|
use anyhow::Result;
|
||||||
use epd_waveshare::{epd7in3f::Epd7in3f, prelude::WaveshareDisplay};
|
use epd_waveshare::{epd7in3f::Epd7in3f, prelude::WaveshareDisplay};
|
||||||
|
use linux_embedded_hal::gpio_cdev::{Chip, LineRequestFlags};
|
||||||
use linux_embedded_hal::spidev::SpiModeFlags;
|
use linux_embedded_hal::spidev::SpiModeFlags;
|
||||||
use linux_embedded_hal::spidev::SpidevOptions;
|
use linux_embedded_hal::spidev::SpidevOptions;
|
||||||
use linux_embedded_hal::{CdevPin, Delay, SpidevDevice};
|
use linux_embedded_hal::{CdevPin, Delay, SpidevDevice};
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use tracing::{debug, warn};
|
use tracing::span;
|
||||||
|
use tracing::{debug, error, info, warn, Level};
|
||||||
use anyhow::Result;
|
|
||||||
use linux_embedded_hal::gpio_cdev::{Chip, LineRequestFlags};
|
|
||||||
|
|
||||||
use crate::dither::DitheredImage;
|
|
||||||
|
|
||||||
pub trait EInkPanel {
|
pub trait EInkPanel {
|
||||||
fn display(&mut self, buf: &DitheredImage) -> Result<()>;
|
fn display(&mut self, buf: &DitheredImage) -> Result<()>;
|
||||||
|
@ -88,3 +90,34 @@ impl EInkPanel for FakeEInk {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a thread that can take dithered images and display them. This allows the display to be
|
||||||
|
/// used in an async context since updating the display can take ~30 seconds.
|
||||||
|
#[must_use]
|
||||||
|
pub fn create_display_thread(
|
||||||
|
mut display: Box<dyn EInkPanel + Send>,
|
||||||
|
) -> (thread::JoinHandle<()>, mpsc::Sender<Box<DitheredImage>>) {
|
||||||
|
let (tx, rx) = mpsc::channel::<Box<DitheredImage>>();
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
let span = span!(Level::INFO, "display_thread");
|
||||||
|
let _enter = span.enter();
|
||||||
|
loop {
|
||||||
|
let res = rx.recv();
|
||||||
|
match res {
|
||||||
|
Ok(img) => {
|
||||||
|
info!("Received an image to display");
|
||||||
|
if let Err(e) = display.display(&img) {
|
||||||
|
error!("Error displaying image: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
info!("Successfully set display image");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error reading image from channel: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
(handle, tx)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue