diff --git a/Cargo.lock b/Cargo.lock index 952addd..5be078f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,13 +37,28 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] +[[package]] +name = "andotp-import" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e4375a7f794f05aaaf899b684307a837fd73c773888cbb01a0f622eed59e43" +dependencies = [ + "byteorder", + "ring", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "totp-rs", +] + [[package]] name = "android-activity" version = "0.4.3" @@ -113,6 +128,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +[[package]] +name = "base32" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" + [[package]] name = "base64" version = "0.21.4" @@ -143,6 +164,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "block-sys" version = "0.1.0-beta.1" @@ -191,14 +221,14 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "calloop" @@ -292,6 +322,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "constant_time_eq" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" + [[package]] name = "core-foundation" version = "0.9.3" @@ -345,6 +381,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -393,6 +438,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "ctor" version = "0.2.5" @@ -400,7 +455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" dependencies = [ "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -409,6 +464,17 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -644,7 +710,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -668,6 +734,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "gethostname" version = "0.3.0" @@ -774,6 +850,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "human-sort" version = "0.2.2" @@ -900,9 +985,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] @@ -939,9 +1024,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libloading" @@ -1235,9 +1320,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -1281,7 +1366,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1439,9 +1524,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -1501,6 +1586,7 @@ dependencies = [ name = "raspi-oled" version = "0.1.0" dependencies = [ + "andotp-import", "display-interface-spi", "embedded-graphics", "embedded-hal 0.2.7", @@ -1509,6 +1595,7 @@ dependencies = [ "libc", "linux-embedded-hal", "rand_xoshiro", + "rpassword", "rppal", "rusqlite", "serde", @@ -1518,6 +1605,7 @@ dependencies = [ "ssd1351", "time", "time-tz", + "totp-rs", "ureq", "winit", ] @@ -1559,9 +1647,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.6" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87" dependencies = [ "aho-corasick", "memchr", @@ -1571,9 +1659,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b" dependencies = [ "aho-corasick", "memchr", @@ -1582,9 +1670,34 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "56d84fdd47036b038fc80dd333d10b6aab10d5d31f4a366e20014def75328d33" + +[[package]] +name = "ring" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.48.0", +] + +[[package]] +name = "rpassword" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +dependencies = [ + "libc", + "rtoolbox", + "winapi", +] [[package]] name = "rppal" @@ -1601,6 +1714,16 @@ dependencies = [ "void", ] +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "rusqlite" version = "0.27.0" @@ -1676,7 +1799,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1711,6 +1834,28 @@ dependencies = [ "termios", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -1850,6 +1995,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -1863,9 +2014,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -1907,7 +2058,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2034,6 +2185,19 @@ dependencies = [ "winnow", ] +[[package]] +name = "totp-rs" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3504f96adf86d28e7eb16fa236a7951ec72c15ee100d1b5318e225944bc8cb" +dependencies = [ + "base32", + "constant_time_eq", + "hmac", + "sha1", + "sha2", +] + [[package]] name = "tracing" version = "0.1.37" @@ -2057,6 +2221,12 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -2078,6 +2248,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "ureq" version = "2.8.0" @@ -2152,7 +2328,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -2174,7 +2350,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2533,9 +2709,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 3ae7c41..3ac59ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,9 @@ winit = { version = "0.28.7", optional = true } softbuffer = { version = "0.3.1", optional = true } rand_xoshiro = "0.6.0" gpiocdev = "0.6.0" +rpassword = "7.2.0" +andotp-import = "0.1.0" +totp-rs = "5.4.0" #gpio-am2302-rs = { git = "https://github.com/FliegendeWurst/gpio-am2302-rs" } [features] diff --git a/src/bin/draw/measurements.rs b/src/bin/draw/measurements.rs index 278d7ed..624df93 100644 --- a/src/bin/draw/measurements.rs +++ b/src/bin/draw/measurements.rs @@ -1,4 +1,4 @@ -use std::{fs, ops::Sub, sync::atomic::AtomicBool, time::Duration}; +use std::{any::Any, fs, ops::Sub, sync::atomic::AtomicBool, time::Duration}; use embedded_graphics::{ image::ImageRaw, @@ -419,4 +419,12 @@ impl> Draw for Measurements { fn draw(&self, disp: &mut D, rng: &mut crate::Rng) -> Result::Error> { panic!("draw without ctx"); } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } diff --git a/src/bin/draw/mod.rs b/src/bin/draw/mod.rs index e2cb2f9..de447db 100644 --- a/src/bin/draw/mod.rs +++ b/src/bin/draw/mod.rs @@ -1,2 +1,4 @@ mod measurements; pub use measurements::Measurements; +mod totp; +pub use totp::Totp; diff --git a/src/bin/draw/totp.rs b/src/bin/draw/totp.rs new file mode 100644 index 0000000..9011738 --- /dev/null +++ b/src/bin/draw/totp.rs @@ -0,0 +1,111 @@ +use std::{any::Any, cell::RefCell}; + +use andotp_import::Account; +use embedded_graphics::{ + mono_font::{ + ascii::{FONT_10X20, FONT_9X15}, + MonoTextStyleBuilder, + }, + pixelcolor::Rgb565, + prelude::*, + text::Text, + Drawable, +}; +use totp_rs::TOTP; + +use crate::{screensaver::Screensaver, Context, ContextDefault, Draw, BLACK}; + +#[derive(Debug, Clone)] +pub struct Totp { + codes: RefCell>, + secrets: Vec<(Account, TOTP)>, + page: usize, +} + +impl Totp { + pub fn new(secrets: Vec<(Account, TOTP)>) -> Self { + Self { + codes: RefCell::new(vec![]), + secrets, + page: 0, + } + } + + pub fn next_page(&mut self) { + self.page += 1; + } +} + +impl> Screensaver for Totp { + fn id(&self) -> &'static str { + "totp" + } + + fn convert_draw(&self) -> Box> { + Box::new(Totp { + codes: RefCell::new(vec![]), + secrets: self.secrets.clone(), + page: 0, + }) + } +} + +impl> Draw for Totp { + fn draw(&self, disp: &mut D, _rng: &mut crate::Rng) -> Result::Error> { + let codes: Vec<_> = self + .secrets + .iter() + .skip(self.page * 6) + .take(6) + .map(|x| (&x.0.issuer, &x.0.label, x.1.generate_current().unwrap())) + .collect(); + if codes.len() == self.codes.borrow().len() + && codes.iter().zip(self.codes.borrow().iter()).all(|(x, y)| &x.2 == y) + { + return Ok(false); + } + *self.codes.borrow_mut() = codes.iter().map(|x| x.2.clone()).collect(); + disp.clear(BLACK)?; + let mut y = 16; + + let text_style_code = MonoTextStyleBuilder::new() + .font(&FONT_10X20) + .text_color(Rgb565::new(0xff, 0xff, 0xff)) + .build(); + let text_style_label = MonoTextStyleBuilder::new() + .font(&FONT_9X15) + .text_color(Rgb565::new(0xff, 0xff, 0xff)) + .build(); + + for (issuer, label, code) in codes { + Text::new(&code, Point::new(0, y), text_style_code).draw(disp)?; + let label_text = if issuer != "" { + issuer + } else if let Some((issuer, _label)) = label.split_once(" - ") { + issuer + } else { + label + }; + Text::new( + if label_text.len() > 7 { + &label_text[0..7] + } else { + label_text + }, + Point::new(60, y), + text_style_label, + ) + .draw(disp)?; + y += 20 + 1; + } + Ok(true) + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} diff --git a/src/bin/main_loop.rs b/src/bin/main_loop.rs index 753afe0..c388f00 100644 --- a/src/bin/main_loop.rs +++ b/src/bin/main_loop.rs @@ -1,7 +1,9 @@ #![feature(array_windows, round_char_boundary)] use std::{ + any::Any, cell::RefCell, + env, rc::Rc, thread, time::{Duration, Instant}, @@ -9,6 +11,7 @@ use std::{ use action::Action; use display_interface_spi::SPIInterfaceNoCS; +use draw::Totp; use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; use gpiocdev::line::{Bias, EdgeDetection, Value}; use rand_xoshiro::{rand_core::SeedableRng, Xoroshiro128StarStar}; @@ -75,6 +78,10 @@ impl> ContextDefault { } } + fn add(&mut self, totp: Totp) { + self.screensavers.push(Box::new(totp)); + } + fn loop_iter(&mut self, disp: &mut D, rng: &mut Rng) -> bool { let time = OffsetDateTime::now_utc().to_timezone(BERLIN); // check schedules @@ -138,7 +145,7 @@ fn pc_main() {} #[cfg(feature = "pc")] fn pc_main() { - use std::{env, num::NonZeroU32}; + use std::num::NonZeroU32; use winit::{ dpi::LogicalSize, @@ -173,7 +180,12 @@ fn pc_main() { let mut buffer_dirty = true; let mut ctx = ContextDefault::new(); - ctx.do_action(Action::Screensaver("measurements")); + if args.iter().any(|x| x == "--totp") { + let pw = rpassword::prompt_password("TOTP password: ").unwrap(); + let totps = andotp_import::read_from_file("./otp_accounts_2023-10-02_18-58-25.json.aes", &pw).unwrap(); + ctx.add(Totp::new(totps)); + ctx.do_action(Action::Screensaver("totp")); + } let mut rng = Xoroshiro128StarStar::seed_from_u64(17381); event_loop.run(move |event, _, control_flow| { @@ -242,16 +254,20 @@ fn pc_main() { } pub trait Draw> { - fn draw_with_ctx(&self, ctx: &ContextDefault, disp: &mut D, rng: &mut Rng) -> Result { + fn draw_with_ctx(&self, _ctx: &ContextDefault, disp: &mut D, rng: &mut Rng) -> Result { self.draw(disp, rng) } fn draw(&self, disp: &mut D, rng: &mut Rng) -> Result; fn expired(&self) -> bool { false } + fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; } fn rpi_main() { + let args: Vec<_> = env::args().map(|x| x.to_string()).collect(); + let spi = Spi::new(Bus::Spi0, SlaveSelect::Ss0, 19660800, Mode::Mode0).unwrap(); let gpio = Gpio::new().unwrap(); let dc = gpio.get(25).unwrap().into_output(); @@ -268,7 +284,14 @@ fn rpi_main() { // Init PWM handling let pwm = thread::spawn(handle_pwm); - main_loop(disp); + let mut ctx = ContextDefault::new(); + if args.iter().any(|x| x == "--totp") { + let pw = rpassword::prompt_password("TOTP password: ").unwrap(); + let totps = andotp_import::read_from_file("./otp_accounts_2023-10-02_18-58-25.json.aes", &pw).unwrap(); + ctx.add(Totp::new(totps)); + } + + main_loop(disp, ctx); let _ = pwm.join(); } @@ -296,10 +319,9 @@ fn handle_pwm() { } } -fn main_loop(mut disp: Oled) { +fn main_loop(mut disp: Oled, mut ctx: ContextDefault) { disp.clear(BLACK).unwrap(); - let mut ctx = ContextDefault::new(); let mut rng = Xoroshiro128StarStar::seed_from_u64(17381); let mut last_button = Instant::now(); @@ -368,11 +390,19 @@ fn main_loop(mut disp: Oled) { let _ = ctx.pop_action_and_clear(&mut disp); disable_pwm().unwrap(); let _ = disp.flush(); + clear = true; } }, - [3] => {}, + [3] => { + ctx.do_action(Action::Screensaver("totp")); + }, [3, 1] => { - enable_pwm().unwrap(); + if let Some(x) = ctx.active.borrow_mut().last_mut() { + let totp: Option<&mut Totp> = x.as_any_mut().downcast_mut(); + if let Some(x) = totp { + x.next_page(); + } + } pop_last = true; }, [3, 2] => { diff --git a/src/bin/screensaver/mod.rs b/src/bin/screensaver/mod.rs index e6fec54..f7a01bb 100644 --- a/src/bin/screensaver/mod.rs +++ b/src/bin/screensaver/mod.rs @@ -1,3 +1,4 @@ +use std::any::Any; use std::cell::RefCell; use std::sync::atomic::{AtomicU32, AtomicU64}; @@ -80,6 +81,14 @@ impl> Draw for SimpleScreensaver { fn expired(&self) -> bool { self.iters.load(std::sync::atomic::Ordering::Relaxed) > 1000 } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } impl SimpleScreensaver { @@ -158,6 +167,14 @@ impl> Draw for TimeDisplay { .draw(disp)?; Ok(true) } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } pub static STAR: SimpleScreensaver = SimpleScreensaver::new("star", include_bytes!("./star.raw"));