Expiration system

This commit is contained in:
FliegendeWurst 2023-10-05 12:56:25 +02:00
parent ca73b6545a
commit 13c5a472ce
8 changed files with 90 additions and 87 deletions

6
Cargo.lock generated
View File

@ -1934,6 +1934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe"
dependencies = [
"deranged",
"js-sys",
"serde",
"time-core",
"time-macros",
@ -1956,9 +1957,9 @@ dependencies = [
[[package]]
name = "time-tz"
version = "1.0.3"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a422f65dfdf08a81317d54fa00b45dc58cbccab69be78c1447391cc39ae8c9d4"
checksum = "733bc522e97980eb421cbf381160ff225bd14262a48a739110f6653c6258d625"
dependencies = [
"cfg-if",
"parse-zoneinfo",
@ -1967,6 +1968,7 @@ dependencies = [
"serde",
"serde-xml-rs",
"time",
"wasm-bindgen",
]
[[package]]

View File

@ -13,7 +13,7 @@ embedded-hal = "0.2.5"
libc = "0.2.98"
rusqlite = "0.27.0"
time = { version = "0.3.9", features = ["parsing"] }
time-tz = "1.0.1"
time-tz = "2"
image = { version = "0.24.1", optional = true }
serde_json = "1.0.79"
serde_derive = "1.0.136"

View File

@ -16,7 +16,7 @@ rustPlatform.buildRustPackage {
nativeBuildInputs = [ pkg-config ];
cargoBuildFlags = [ "--no-default-features" ];
cargoBuildFlags = [ "--no-default-features" "--bin" "main_loop" ];
buildInputs = [ sqlite ];

View File

@ -1,3 +1,5 @@
#![feature(array_windows)]
use std::{
cell::RefCell,
thread,
@ -67,7 +69,21 @@ impl<D: DrawTarget<Color = Rgb565>> ContextDefault<D> {
return false;
}
let a = active.last().unwrap();
a.draw(disp, rng).unwrap_or(true)
if !a.expired() {
return a.draw(disp, rng).unwrap_or(true);
}
drop(active);
self.active.borrow_mut().pop();
self.loop_iter(disp, rng)
}
fn pop_action_and_clear(&mut self, disp: &mut D) -> Result<(), D::Error> {
let active = self.active.get_mut();
if active.len() > 1 {
active.pop();
disp.clear(BLACK)?;
}
Ok(())
}
}
@ -78,8 +94,10 @@ impl<D: DrawTarget<Color = Rgb565>> Context for ContextDefault<D> {
for s in &self.screensavers {
if s.id() == id {
self.active.borrow_mut().push(s.convert_draw());
return;
}
}
println!("warning: screensaver not found");
},
}
}
@ -90,7 +108,7 @@ fn pc_main() {}
#[cfg(feature = "pc")]
fn pc_main() {
use std::num::NonZeroU32;
use std::{env, num::NonZeroU32};
use winit::{
dpi::LogicalSize,
@ -102,6 +120,16 @@ fn pc_main() {
use crate::screensaver::{Screensaver, DUOLINGO};
use raspi_oled::FrameOutput;
let args: Vec<_> = env::args().map(|x| x.to_string()).collect();
for [key, val] in args.array_windows() {
match key.as_str() {
"--speed" => {
screensaver::SPEED.store(val.parse().unwrap(), std::sync::atomic::Ordering::Relaxed);
},
_ => {},
}
}
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_inner_size(LogicalSize::new(128, 128))
@ -116,6 +144,7 @@ fn pc_main() {
let mut buffer_dirty = true;
let mut ctx = ContextDefault::new();
ctx.do_action(Action::Screensaver("plate"));
let mut rng = Xoroshiro128StarStar::seed_from_u64(17381);
event_loop.run(move |event, _, control_flow| {
@ -156,81 +185,9 @@ fn pc_main() {
.unwrap();
// redraw
if Instant::now().duration_since(start) > Duration::from_millis(iters * 1000) {
if Instant::now().duration_since(start) > Duration::from_millis(iters * 66) {
iters += 1;
buffer_dirty = ctx.loop_iter(&mut disp, &mut rng);
//loop_iter(&mut disp).unwrap();
/*
let mut time = OffsetDateTime::now_utc().to_timezone(BERLIN);
//time += Duration::new(iters * 60, 0);
disp.clear(Rgb565::new(0, 0, 0)).unwrap();
display_clock(&mut disp, &time).unwrap();
*/
//DUOLINGO.draw(&mut disp, &mut rng).unwrap();
/*
let iters = iters % 300;
let (s, c) = (iters as f32 * 0.1).sin_cos();
let (mut x, mut y) = (s * iters as f32 * 0.005, c * iters as f32 * 0.005);
x *= 64.;
y *= 64.;
x += 64.;
y += 64.;
let variation = iters as u32 / 16 + 1;
for _ in 0..16 {
let dx = (rng.next_u32() % variation) as i32 - variation as i32 / 2;
let dy = (rng.next_u32() % variation) as i32 - variation as i32 / 2;
let color = rng.next_u32();
let p = Rectangle::new(Point::new(x as i32 + dx, y as i32 + dy), Size::new(1, 1));
let s = PrimitiveStyleBuilder::new()
.fill_color(Rgb565::new(
color as u8 & 0b11111,
((color >> 8) & 0b111111) as u8,
((color >> 16) & 0b111111) as u8,
))
.build();
p.draw_styled(&s, &mut disp).unwrap();
}
if iters % 300 == 0 {
disp.clear(Rgb565::new(0, 0, 0)).unwrap();
}
*/
/*
for _ in 0..16 {
let x = (rng.next_u32() % 128) as usize;
let y = (rng.next_u32() % 128) as usize;
let dx = (rng.next_u32() % 8) as i32 - 4;
let dy = (rng.next_u32() % 8) as i32 - 4;
let red = STAR[y * 128 * 3 + x * 3];
let green = STAR[y * 128 * 3 + x * 3 + 1];
if red == 0xff {
let color = rng.next_u32();
let r;
let g;
let b;
// star
r = (color as u8 & 0b11111).saturating_mul(2);
g = (((color >> 8) & 0b111111) as u8).saturating_mul(2);
b = ((color >> 16) & 0b111111) as u8 / 3;
// rpi
/*
if red > green {
r = (color as u8 & 0b11111).saturating_mul(2);
g = ((color >> 8) & 0b111111) as u8 / 3;
b = ((color >> 16) & 0b111111) as u8 / 3;
} else {
r = (color as u8 & 0b11111) / 2;
g = (((color >> 8) & 0b111111) as u8).saturating_mul(2);
b = ((color >> 16) & 0b111111) as u8 / 3;
}
*/
let p = Rectangle::new(Point::new(x as i32 + dx, y as i32 + dy), Size::new(1, 1));
let s = PrimitiveStyleBuilder::new()
.fill_color(Rgb565::new(r as u8, g as u8, b as u8))
.build();
p.draw_styled(&s, &mut disp).unwrap();
}
}
*/
}
let mut buffer = surface.buffer_mut().unwrap();
@ -256,6 +213,9 @@ fn pc_main() {
pub trait Draw<D: DrawTarget<Color = Rgb565>> {
fn draw(&self, disp: &mut D, rng: &mut Rng) -> Result<bool, D::Error>;
fn expired(&self) -> bool {
false
}
}
fn rpi_main() {
@ -318,7 +278,6 @@ fn main_loop(mut disp: Oled) {
},
6 => {
menu.push(2);
ctx.do_action(Action::Screensaver("rpi"));
},
5 => {
menu.push(3);
@ -327,6 +286,15 @@ fn main_loop(mut disp: Oled) {
println!("unknown offset: {}", e.offset);
},
}
match &*menu {
[2] => {
let _ = ctx.pop_action_and_clear(&mut disp);
},
[3] => {
ctx.do_action(Action::Screensaver("rpi"));
},
_ => {},
}
//println!("menu: {menu:?}");
}
// clean up stale menu selection
@ -338,6 +306,6 @@ fn main_loop(mut disp: Oled) {
if dirty {
let _ = disp.flush(); // ignore bus write errors, they are harmless
}
thread::sleep(Duration::from_millis(1000));
thread::sleep(Duration::from_millis(66));
}
}

View File

@ -40,6 +40,8 @@ impl Reminder {
static DUOLINGO: Reminder = Reminder::new(11, 30, Action::Screensaver("duolingo"));
static DUOLINGO_NIGHT: Reminder = Reminder::new(23, 30, Action::Screensaver("duolingo"));
static FOOD: Reminder = Reminder::new(13, 15, Action::Screensaver("plate"));
pub fn reminders() -> Vec<Box<dyn Schedule>> {
vec![Box::new(DUOLINGO), Box::new(DUOLINGO_NIGHT)]
vec![Box::new(DUOLINGO), Box::new(DUOLINGO_NIGHT), Box::new(FOOD)]
}

View File

@ -1,4 +1,5 @@
use std::cell::RefCell;
use std::sync::atomic::{AtomicU32, AtomicU64};
use embedded_graphics::mono_font::ascii::FONT_10X20;
use embedded_graphics::{
@ -15,15 +16,28 @@ use time_tz::{timezones::db::europe::BERLIN, OffsetDateTimeExt};
use crate::{Draw, Rng};
pub static SPEED: AtomicU64 = AtomicU64::new(32);
pub trait Screensaver<D: DrawTarget<Color = Rgb565>>: Draw<D> {
fn id(&self) -> &'static str;
fn convert_draw(&self) -> Box<dyn Draw<D>>;
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug)]
pub struct SimpleScreensaver {
id: &'static str,
data: &'static [u8],
iters: AtomicU32,
}
impl Clone for SimpleScreensaver {
fn clone(&self) -> Self {
Self {
id: self.id,
data: self.data,
iters: AtomicU32::new(self.iters.load(std::sync::atomic::Ordering::Relaxed)),
}
}
}
impl<D: DrawTarget<Color = Rgb565>> Screensaver<D> for SimpleScreensaver {
@ -32,13 +46,13 @@ impl<D: DrawTarget<Color = Rgb565>> Screensaver<D> for SimpleScreensaver {
}
fn convert_draw(&self) -> Box<dyn Draw<D>> {
Box::new(*self)
Box::new(self.clone())
}
}
impl<D: DrawTarget<Color = Rgb565>> Draw<D> for SimpleScreensaver {
fn draw(&self, disp: &mut D, rng: &mut Rng) -> Result<bool, D::Error> {
for _ in 0..512 {
for _ in 0..SPEED.load(std::sync::atomic::Ordering::Relaxed) {
let x = (rng.next_u32() % 128) as usize;
let y = (rng.next_u32() % 128) as usize;
let dx = (rng.next_u32() % 8) as i32 - 4;
@ -59,8 +73,13 @@ impl<D: DrawTarget<Color = Rgb565>> Draw<D> for SimpleScreensaver {
p.draw_styled(&s, disp)?;
}
}
self.iters.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Ok(true)
}
fn expired(&self) -> bool {
self.iters.load(std::sync::atomic::Ordering::Relaxed) > 1000
}
}
impl SimpleScreensaver {
@ -68,7 +87,11 @@ impl SimpleScreensaver {
if data.len() != 128 * 128 * 3 {
panic!("invalid screensaver size");
}
SimpleScreensaver { id, data }
SimpleScreensaver {
id,
data,
iters: AtomicU32::new(0),
}
}
}
@ -140,7 +163,15 @@ impl<D: DrawTarget<Color = Rgb565>> Draw<D> for TimeDisplay {
pub static STAR: SimpleScreensaver = SimpleScreensaver::new("star", include_bytes!("./star.raw"));
pub static RPI: SimpleScreensaver = SimpleScreensaver::new("rpi", include_bytes!("./rpi.raw"));
pub static DUOLINGO: SimpleScreensaver = SimpleScreensaver::new("duolingo", include_bytes!("./duolingo.raw"));
pub static SPAGHETTI: SimpleScreensaver = SimpleScreensaver::new("spaghetti", include_bytes!("./spaghetti.raw"));
pub static PLATE: SimpleScreensaver = SimpleScreensaver::new("plate", include_bytes!("./plate.raw"));
pub fn screensavers<D: DrawTarget<Color = Rgb565>>() -> Vec<Box<dyn Screensaver<D>>> {
vec![Box::new(STAR), Box::new(RPI), Box::new(DUOLINGO)]
vec![
Box::new(STAR.clone()),
Box::new(RPI.clone()),
Box::new(DUOLINGO.clone()),
Box::new(SPAGHETTI.clone()),
Box::new(PLATE.clone()),
]
}

Binary file not shown.

Binary file not shown.