Author SHA1 Message Date
rhetenor 2bab03351b refactor: move views to views sub folder 2026-08-18 19:24:50 +00:00
rhetenor ea3bd5c10b wokwi: switch back and ok button 2026-08-18 18:55:24 +00:00
rhetenor 8a7456adbd implement back button 2026-08-18 18:53:17 +00:00
ede1998 9792385af1 beautify scan menu 2026-08-15 00:17:37 +02:00
rhetenor 890a0e5d62 implement settings menu 2026-08-14 21:57:32 +00:00
rhetenor e1ab69d1ab move menu drawing to own function 2026-08-14 21:40:24 +00:00
ede1998 0fb87f2913 Split into multi-menu 2026-08-14 23:31:36 +02:00
rhetenor 6c683e415f main menu: wrap around correctly 2026-08-14 21:18:08 +00:00
ede1998 d3ac95a9bd add scan menu 2026-08-14 23:06:49 +02:00
rhetenor 77b73902b8 simple button debounce 2026-08-14 21:00:16 +00:00
rhetenor e361154295 try to workout buttons 2026-08-14 20:47:44 +00:00
rhetenor ca4ea67e7b update wokwi with buttons 2026-08-14 20:36:18 +00:00
rhetenor f38181d98a main menu first simple implementation of display and state 2026-08-14 20:20:53 +00:00
rhetenor 6b8d076b3c working on main menu 2026-08-14 20:02:11 +00:00
rhetenor 88dce365ad implement basic embassy framework 2026-08-14 19:14:44 +00:00
27 changed files with 546 additions and 803 deletions
Generated
+9 -133
View File
@@ -229,16 +229,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "ch1115"
version = "0.1.2"
source = "git+https://github.com/ede1998/ch1115.git?rev=2d3a3ba38050efe012e6a210afe3e125ec280c37#2d3a3ba38050efe012e6a210afe3e125ec280c37"
dependencies = [
"display-interface",
"embedded-graphics-core",
"embedded-hal 1.0.0",
]
[[package]] [[package]]
name = "cobs" name = "cobs"
version = "0.3.0" version = "0.3.0"
@@ -313,16 +303,15 @@ name = "creaturedex"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"ch1115",
"critical-section", "critical-section",
"display-interface-spi", "display-interface-spi",
"embassy-executor", "embassy-executor",
"embassy-futures",
"embassy-time", "embassy-time",
"embedded-graphics", "embedded-graphics",
"embedded-graphics-core", "embedded-graphics-core",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
"embedded-hal-bus", "embedded-hal-bus",
"embedded-hal-compat",
"embedded-io 0.7.1", "embedded-io 0.7.1",
"esp-alloc", "esp-alloc",
"esp-bootloader-esp-idf", "esp-bootloader-esp-idf",
@@ -334,8 +323,6 @@ dependencies = [
"log", "log",
"ndef", "ndef",
"pn532", "pn532",
"sh1106",
"ssd1306",
] ]
[[package]] [[package]]
@@ -620,17 +607,6 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba2aab1ef3793e6f7804162debb5ac5edb93b3d650fbcc5aeb72fcd0e6c03a0" checksum = "7ba2aab1ef3793e6f7804162debb5ac5edb93b3d650fbcc5aeb72fcd0e6c03a0"
[[package]]
name = "display-interface-i2c"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d964fa85bbbb5a6ecd06e58699407ac5dc3e3ad72dac0ab7e6b0d00a1cd262d"
dependencies = [
"display-interface",
"embedded-hal 1.0.0",
"embedded-hal-async",
]
[[package]] [[package]]
name = "display-interface-spi" name = "display-interface-spi"
version = "0.5.0" version = "0.5.0"
@@ -970,17 +946,6 @@ dependencies = [
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
] ]
[[package]]
name = "embedded-hal-compat"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ecac72f6be75ad2d4809c9f07d45502e2e5c9a4e9579077f28d7135de81df3"
dependencies = [
"embedded-hal 0.2.7",
"embedded-hal 1.0.0",
"nb 1.1.0",
]
[[package]] [[package]]
name = "embedded-io" name = "embedded-io"
version = "0.4.0" version = "0.4.0"
@@ -1566,27 +1531,27 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.33" version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.33" version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.33" version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.33" version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-task", "futures-task",
@@ -1952,30 +1917,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
[[package]]
name = "manyhow"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587"
dependencies = [
"manyhow-macros",
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.119",
]
[[package]]
name = "manyhow-macros"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495"
dependencies = [
"proc-macro-utils",
"proc-macro2",
"quote",
]
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.2.0" version = "0.2.0"
@@ -1991,19 +1932,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "maybe-async-cfg"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627"
dependencies = [
"manyhow",
"proc-macro2",
"pulldown-cmark",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.3" version = "2.8.3"
@@ -2763,17 +2691,6 @@ dependencies = [
"toml_edit", "toml_edit",
] ]
[[package]]
name = "proc-macro-utils"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071"
dependencies = [
"proc-macro2",
"quote",
"smallvec",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.107" version = "1.0.107"
@@ -2803,17 +2720,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "pulldown-cmark"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
dependencies = [
"bitflags 2.13.1",
"memchr",
"unicase",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.47" version = "1.0.47"
@@ -3140,16 +3046,6 @@ dependencies = [
"unsafe-libyaml", "unsafe-libyaml",
] ]
[[package]]
name = "sh1106"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc12a0563ec9b3b1f99b1f64613581ebbade1347416a34766564f406c15d1bf3"
dependencies = [
"embedded-graphics-core",
"embedded-hal 0.2.7",
]
[[package]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.7" version = "0.1.7"
@@ -3238,20 +3134,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c" checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c"
[[package]]
name = "ssd1306"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ed51935bdc6e9e976d3d9a747e768589eaea0cf26f483213bfededc947c8624"
dependencies = [
"display-interface",
"display-interface-i2c",
"display-interface-spi",
"embedded-graphics-core",
"embedded-hal 1.0.0",
"maybe-async-cfg",
]
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.1" version = "1.2.1"
@@ -3519,12 +3401,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
[[package]]
name = "unicase"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
[[package]] [[package]]
name = "unicode-id-start" name = "unicode-id-start"
version = "1.4.0" version = "1.4.0"
+4 -10
View File
@@ -9,7 +9,7 @@ name = "creaturedex"
path = "./src/bin/main.rs" path = "./src/bin/main.rs"
[dependencies] [dependencies]
esp-hal = { version = "~1.1.0", features = ["esp32s3", "log-04", "unstable"] } esp-hal = { version = "~1.1.0", features = ["esp32s3", "log-04", "unstable"] } #, "embassy", "embassy-time-timg0", "embassy-executor-thread"] }
esp-rtos = { version = "0.3.0", features = [ esp-rtos = { version = "0.3.0", features = [
"embassy", "embassy",
@@ -24,8 +24,10 @@ log = "0.4.27"
critical-section = "1.2.0" critical-section = "1.2.0"
embedded-io = "0.7.1" embedded-io = "0.7.1"
embassy-executor = { version = "0.10.0", default-features = false } embassy-executor = { version = "0.10.0", features = [
] }
embassy-time = { version = "0.5.1", default-features = false } embassy-time = { version = "0.5.1", default-features = false }
embassy-futures = "0.1.2"
esp-alloc = "0.10.0" esp-alloc = "0.10.0"
esp-hal-wifimanager = { git = "https://github.com/InvisibleUSA/esp-hal-wifimanager", default-features = false, features = [ esp-hal-wifimanager = { git = "https://github.com/InvisibleUSA/esp-hal-wifimanager", default-features = false, features = [
"ap", "ap",
@@ -34,7 +36,6 @@ esp-hal-wifimanager = { git = "https://github.com/InvisibleUSA/esp-hal-wifimanag
esp-println = { version = "0.17.0", features = ["esp32s3", "log-04"] } esp-println = { version = "0.17.0", features = ["esp32s3", "log-04"] }
display-interface-spi = "0.5.0" display-interface-spi = "0.5.0"
ili9341 = "0.6.0" ili9341 = "0.6.0"
ssd1306 = "0.9.0"
embedded-hal = "1.0.0" embedded-hal = "1.0.0"
embedded-hal-bus = "0.3.0" embedded-hal-bus = "0.3.0"
embedded-graphics = "0.8.2" embedded-graphics = "0.8.2"
@@ -42,13 +43,6 @@ embedded-graphics-core = "0.4.1"
base64 = { version = "0.22", default-features = false, features = ["alloc"] } base64 = { version = "0.22", default-features = false, features = ["alloc"] }
pn532 = "0.5.0" pn532 = "0.5.0"
ndef = "0.5.0" ndef = "0.5.0"
ch1115 = { version = "0.1.2", features = ["graphics"] }
sh1106 = "0.5.0"
embedded-hal-compat = "0.13.0"
[patch.crates-io]
ch1115 = { git = "https://github.com/ede1998/ch1115.git", rev = "2d3a3ba38050efe012e6a210afe3e125ec280c37" }
# For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html # For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html
[profile.dev] [profile.dev]
+81 -36
View File
@@ -1,37 +1,82 @@
{ {
"version": 1, "version": 1,
"author": "CreatureDex", "author": "CreatureDex",
"editor": "wokwi", "editor": "wokwi",
"parts": [ "parts": [
{ {
"type": "board-esp32-s3-devkitc-1", "type": "board-esp32-s3-devkitc-1",
"id": "esp1", "id": "esp1",
"top": 67.2, "top": 67.2,
"left": -263.96, "left": -263.96,
"attrs": {} "attrs": {}
}, },
{ "type": "wokwi-ili9341", "id": "lcd1", "top": -191.24, "left": -0.38, "attrs": {} }, { "type": "wokwi-ili9341", "id": "lcd1", "top": -200.8, "left": 354.9, "attrs": {} },
{ {
"type": "wokwi-pushbutton", "type": "wokwi-pushbutton",
"id": "btn1", "id": "btn-up",
"top": 131, "top": -99.4,
"left": -124.8, "left": -76.8,
"attrs": { "color": "green", "xray": "1", "key": "1" } "attrs": { "color": "RebeccaPurple", "xray": "1", "key": "1", "label": "Up" }
} },
], {
"connections": [ "type": "wokwi-pushbutton",
[ "esp1:TX", "$serialMonitor:RX", "", [] ], "id": "btn-down",
[ "esp1:RX", "$serialMonitor:TX", "", [] ], "top": 25.4,
[ "lcd1:VCC", "esp1:3V3", "red", [ "v19.2", "h-57.6", "v-105.6", "h-124.95" ] ], "left": -76.8,
[ "lcd1:GND", "esp1:GND.2", "black", [ "v28.8", "h-76.8", "v-76.8" ] ], "attrs": { "color": "green", "xray": "1", "key": "1", "label": "Down" }
[ "lcd1:CS", "esp1:11", "orange", [ "v0" ] ], },
[ "lcd1:D/C", "esp1:12", "gold", [ "v0" ] ], {
[ "lcd1:RESET", "esp1:10", "brown", [ "v0" ] ], "type": "wokwi-pushbutton",
[ "lcd1:MOSI", "esp1:35", "violet", [ "v105.6", "h-124.8", "v-144" ] ], "id": "btn-left",
[ "lcd1:SCK", "esp1:36", "white", [ "v115.2", "h-144", "v-86.4" ] ], "top": -32.2,
[ "esp1:37", "lcd1:MISO", "magenta", [ "h57.6", "v105.6", "h172.8" ] ], "left": -163.2,
[ "btn1:1.l", "esp1:GND.2", "green", [ "h-9.6", "v-48" ] ], "attrs": { "color": "yellow", "xray": "1", "key": "1", "label": "Left" }
[ "btn1:2.l", "esp1:38", "green", [ "h-9.6", "v19.4" ] ] },
], {
"dependencies": {} "type": "wokwi-pushbutton",
} "id": "btn-right",
"top": -32.2,
"left": 19.2,
"attrs": { "color": "red", "xray": "1", "key": "1", "label": "Right" }
},
{
"type": "wokwi-pushbutton",
"id": "btn-back",
"top": -99.4,
"left": 115.2,
"attrs": { "color": "Magenta", "xray": "1", "key": "1", "label": "Back" }
},
{
"type": "wokwi-pushbutton",
"id": "btn-ok",
"top": 25.4,
"left": 115.2,
"attrs": { "color": "Lime", "xray": "1", "key": "1", "label": "Ok" }
}
],
"connections": [
[ "esp1:TX", "$serialMonitor:RX", "", [] ],
[ "esp1:RX", "$serialMonitor:TX", "", [] ],
[ "lcd1:VCC", "esp1:3V3", "red", [ "v19.2", "h-57.6", "v-105.6", "h-124.95" ] ],
[ "lcd1:GND", "esp1:GND.2", "black", [ "v28.8", "h-76.8", "v-76.8" ] ],
[ "lcd1:CS", "esp1:11", "orange", [ "v0" ] ],
[ "lcd1:D/C", "esp1:12", "gold", [ "v0" ] ],
[ "lcd1:RESET", "esp1:10", "brown", [ "v0" ] ],
[ "lcd1:MOSI", "esp1:35", "violet", [ "v105.6", "h-124.8", "v-144" ] ],
[ "lcd1:SCK", "esp1:36", "white", [ "v115.2", "h-144", "v-86.4" ] ],
[ "esp1:37", "lcd1:MISO", "magenta", [ "h57.6", "v105.6", "h172.8" ] ],
[ "btn-up:2.l", "esp1:38", "purple", [ "h-9.6", "v19.4" ] ],
[ "btn-up:1.l", "esp1:GND.2", "black", [ "h0" ] ],
[ "btn-down:1.l", "esp1:GND.2", "black", [ "h0" ] ],
[ "btn-down:2.l", "esp1:39", "green", [ "h-19.2", "v115.4" ] ],
[ "btn-left:2.l", "esp1:40", "yellow", [ "h0", "v173" ] ],
[ "btn-left:1.l", "esp1:GND.2", "black", [ "h0" ] ],
[ "btn-right:2.l", "esp1:41", "red", [ "h-19.2", "v153.8" ] ],
[ "btn-right:1.l", "btn-left:1.r", "black", [ "h-96", "v28.8" ] ],
[ "btn-back:2.l", "esp1:42", "Magenta", [ "h-19.2", "v211.58" ] ],
[ "btn-back:1.l", "btn-up:1.r", "black", [ "h0" ] ],
[ "btn-ok:1.l", "btn-down:1.r", "black", [ "h0" ] ],
[ "btn-ok:2.l", "esp1:45", "Lime", [ "h-9.6", "v173" ] ]
],
"dependencies": {}
}
-106
View File
@@ -1,106 +0,0 @@
#![no_std]
#![no_main]
#![deny(
clippy::mem_forget,
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer."
)]
use ch1115::Ch1115;
use core::cell::RefCell;
use creaturedex::display::shared_bus::SharedPin;
use embassy_executor::Spawner;
use embassy_time::Timer;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::{
mono_font::{MonoTextStyle, ascii::FONT_6X10},
prelude::*,
text::Text,
};
use esp_hal::clock::CpuClock;
use esp_hal::delay::Delay;
use esp_hal::gpio::{Level, Output, OutputConfig};
use esp_hal::spi::Mode;
use esp_hal::spi::master::{Config as SpiConfig, Spi};
use esp_hal::time::Rate;
use esp_hal::timer::timg::TimerGroup;
use log::error;
#[panic_handler]
fn panic(panic_info: &core::panic::PanicInfo) -> ! {
error!("{}", panic_info);
loop {}
}
extern crate alloc;
esp_bootloader_esp_idf::esp_app_desc!();
#[esp_rtos::main]
async fn main(_spawner: Spawner) {
esp_println::logger::init_logger_from_env();
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
// The following GPIO pins are in use by some feature of the module and should not be used.
let _ = peripherals.GPIO27;
let _ = peripherals.GPIO28;
let _ = peripherals.GPIO29;
let _ = peripherals.GPIO30;
let _ = peripherals.GPIO31;
let _ = peripherals.GPIO32;
let _ = peripherals.GPIO33;
let _ = peripherals.GPIO34;
esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 73744);
let mut delay = Delay::new();
let timg0 = TimerGroup::new(peripherals.TIMG0);
let sw_interrupt =
esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0);
let spi = peripherals.SPI2;
let sck = peripherals.GPIO36;
let mosi = peripherals.GPIO35;
let cs = peripherals.GPIO13;
let reset = peripherals.GPIO10;
let dc = peripherals.GPIO12;
let miso = peripherals.GPIO37;
let cs = Output::new(cs, Level::High, OutputConfig::default());
let dc = Output::new(dc, Level::Low, OutputConfig::default());
let reset = Output::new(reset, Level::High, OutputConfig::default());
let spi = Spi::new(
spi,
SpiConfig::default()
.with_frequency(Rate::from_khz(5000))
.with_mode(Mode::_0),
)
.unwrap()
.with_sck(sck)
.with_mosi(mosi)
.with_miso(miso);
let spi = RefCell::new(spi);
let spi_dev = embedded_hal_bus::spi::RefCellDevice::new(&spi, cs, delay).unwrap();
let interface = display_interface_spi::SPIInterface::new(spi_dev, dc);
let mut display = Ch1115::new(interface, reset, ch1115::Size128x64);
display.init(&mut delay).unwrap();
loop {
log::info!("Init finished");
let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On);
Text::new("Hello OLED", Point::new(10, 20), text_style)
.draw(&mut display)
.unwrap();
display.flush().unwrap();
Timer::after_millis(1000).await;
}
}
-121
View File
@@ -1,121 +0,0 @@
#![no_std]
#![no_main]
#![deny(
clippy::mem_forget,
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer."
)]
use embassy_executor::Spawner;
use embassy_time::Timer;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::{
mono_font::{MonoTextStyle, ascii::FONT_6X10},
prelude::*,
text::Text,
};
use embedded_hal_compat::ReverseCompat;
use esp_hal::clock::CpuClock;
use esp_hal::delay::Delay;
use esp_hal::gpio::{Level, Output, OutputConfig};
use esp_hal::spi::Mode;
use esp_hal::spi::master::{Config as SpiConfig, Spi};
use esp_hal::time::Rate;
use esp_hal::timer::timg::TimerGroup;
use log::error;
#[panic_handler]
fn panic(panic_info: &core::panic::PanicInfo) -> ! {
error!("{}", panic_info);
loop {}
}
extern crate alloc;
esp_bootloader_esp_idf::esp_app_desc!();
// This creates a defaembedded_hal_compatedReverseCompat::reverse(Output::new(cs,Level::High,OutputConfig::default()))vel::High,OutputConfig::default())) more information see: embedded_hal_compat::ForwardCompat::forward(Spi::new(spi,SpiConfig::default().with_frequency(Rate::from_khz(100)).with_mode(Mode::_0),).unwrap().with_sck(sck).with_mosi(mosi))rward(Spi::new(spi,SpiConfig::default().with_frequency(Rate::from_khz(100)).with_mode(Mode::_0),).unwrap().with_sck(sck).with_mosi(mosi)) to allocate larger buffers etc. in main"
#[esp_rtos::main]
async fn main(_spawner: Spawner) {
esp_println::logger::init_logger_from_env();
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
// The following GPIO pins are in use by some feature of the module and should not be used.
let _ = peripherals.GPIO27;
let _ = peripherals.GPIO28;
let _ = peripherals.GPIO29;
let _ = peripherals.GPIO30;
let _ = peripherals.GPIO31;
let _ = peripherals.GPIO32;
let _ = peripherals.GPIO33;
let _ = peripherals.GPIO34;
esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 73744);
let delay = Delay::new();
let timg0 = TimerGroup::new(peripherals.TIMG0);
let sw_interrupt =
esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0);
let spi = peripherals.SPI2;
let sck = peripherals.GPIO36;
let mosi = peripherals.GPIO35;
let cs = peripherals.GPIO13;
let reset = peripherals.GPIO10;
let dc = peripherals.GPIO12;
let miso = peripherals.GPIO37;
let cs = Output::new(cs, Level::High, OutputConfig::default()).reverse_cell();
let dc = Output::new(dc, Level::Low, OutputConfig::default()).reverse_cell();
let mut reset = Output::new(reset, Level::High, OutputConfig::default());
let spi = Spi::new(
spi,
SpiConfig::default()
.with_frequency(Rate::from_khz(5000))
.with_mode(Mode::_0),
)
.unwrap()
.with_sck(sck)
.with_mosi(mosi)
.with_miso(miso)
.reverse();
let mut display: sh1106::mode::GraphicsMode<_> =
sh1106::Builder::new().connect_spi(spi, dc, cs).into();
display.init().unwrap();
// Hard reset the OLED
reset.set_high();
delay.delay_millis(1);
reset.set_low();
delay.delay_millis(10);
reset.set_high();
display.flush().unwrap();
display.set_pixel(10, 20, 1);
display.flush().unwrap();
let mut oled = display;
oled.clear();
let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On);
Text::new("Hello OLED", Point::new(10, 20), text_style)
.draw(&mut oled)
.unwrap();
oled.flush().unwrap();
loop {
log::info!("Init finished");
Timer::after_millis(1000).await;
}
}
-122
View File
@@ -1,122 +0,0 @@
#![no_std]
#![no_main]
#![deny(
clippy::mem_forget,
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer."
)]
#![deny(clippy::large_stack_frames)]
use embassy_executor::Spawner;
use embassy_time::Timer;
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::text::Text;
use embedded_graphics::{
mono_font::{MonoTextStyle, ascii::FONT_6X10},
prelude::*,
};
use core::cell::RefCell;
use esp_hal::clock::CpuClock;
use esp_hal::delay::Delay;
use esp_hal::gpio::{Level, Output, OutputConfig};
use esp_hal::spi::Mode;
use esp_hal::spi::master::{Config as SpiConfig, Spi};
use esp_hal::time::Rate;
use esp_hal::timer::timg::TimerGroup;
use log::error;
use ssd1306::Ssd1306;
use ssd1306::mode::DisplayConfig;
use ssd1306::rotation::DisplayRotation;
use ssd1306::size::DisplaySize128x64;
#[panic_handler]
fn panic(panic_info: &core::panic::PanicInfo) -> ! {
error!("{}", panic_info);
loop {}
}
extern crate alloc;
esp_bootloader_esp_idf::esp_app_desc!();
// This creates a defaembedded_hal_compatedReverseCompat::reverse(Output::new(cs,Level::High,OutputConfig::default()))vel::High,OutputConfig::default())) more information see: embedded_hal_compat::ForwardCompat::forward(Spi::new(spi,SpiConfig::default().with_frequency(Rate::from_khz(100)).with_mode(Mode::_0),).unwrap().with_sck(sck).with_mosi(mosi))rward(Spi::new(spi,SpiConfig::default().with_frequency(Rate::from_khz(100)).with_mode(Mode::_0),).unwrap().with_sck(sck).with_mosi(mosi)) to allocate larger buffers etc. in main"
#[esp_rtos::main]
async fn main(_spawner: Spawner) {
esp_println::logger::init_logger_from_env();
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
// The following GPIO pins are in use by some feature of the module and should not be used.
let _ = peripherals.GPIO27;
let _ = peripherals.GPIO28;
let _ = peripherals.GPIO29;
let _ = peripherals.GPIO30;
let _ = peripherals.GPIO31;
let _ = peripherals.GPIO32;
let _ = peripherals.GPIO33;
let _ = peripherals.GPIO34;
esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 73744);
let mut delay = Delay::new();
let timg0 = TimerGroup::new(peripherals.TIMG0);
let sw_interrupt =
esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0);
let spi = peripherals.SPI2;
let sck = peripherals.GPIO36;
let mosi = peripherals.GPIO35;
let cs = peripherals.GPIO13;
let reset = peripherals.GPIO10;
let dc = peripherals.GPIO12;
let miso = peripherals.GPIO37;
let cs = Output::new(cs, Level::High, OutputConfig::default());
let dc = Output::new(dc, Level::Low, OutputConfig::default());
let mut reset = Output::new(reset, Level::High, OutputConfig::default());
let spi = Spi::new(
spi,
SpiConfig::default()
.with_frequency(Rate::from_khz(5000))
.with_mode(Mode::_0),
)
.unwrap()
.with_sck(sck)
.with_mosi(mosi)
.with_miso(miso);
let spi = RefCell::new(spi);
let spi_dev = embedded_hal_bus::spi::RefCellDevice::new(&spi, cs, delay).unwrap();
let interface = display_interface_spi::SPIInterface::new(spi_dev, dc);
let mut display = Ssd1306::new(
interface,
DisplaySize128x64,
DisplayRotation::Rotate0,
)
.into_buffered_graphics_mode();
display.reset(&mut reset, &mut delay).unwrap();
display.init().unwrap();
display.clear(BinaryColor::Off).unwrap();
let mut oled = display;
let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On);
Text::new("Hello OLED", Point::new(10, 20), text_style)
.draw(&mut oled)
.unwrap();
oled.flush().unwrap();
loop {
log::info!("Init finished");
Timer::after_millis(1000).await;
}
}
+34 -53
View File
@@ -7,26 +7,23 @@
)] )]
#![deny(clippy::large_stack_frames)] #![deny(clippy::large_stack_frames)]
use alloc::boxed::Box;
use creaturedex::card::mock::{MOCK_PAYLOAD, MOCK_PAYLOAD2}; use creaturedex::card::mock::{MOCK_PAYLOAD, MOCK_PAYLOAD2};
use creaturedex::display::shared_bus::init_dual_displays; use creaturedex::display::primary_lcd::{PrimaryLcdDisplay, init_primary_lcd};
use creaturedex::display::views::card_view::render_nfc_payload;
use creaturedex::drivers::nfc_pn532::NfcPn532Driver; use creaturedex::drivers::nfc_pn532::NfcPn532Driver;
use creaturedex::navigation::input::init_navigation_button; use creaturedex::navigation::inputs::Inputs;
use creaturedex::navigation::navigation;
use creaturedex::navigation::state::NavigationState; use creaturedex::navigation::state::NavigationState;
use creaturedex::network::wifi::setup_wifi; use creaturedex::network::wifi::setup_wifi;
use creaturedex::views::card_view::render_nfc_payload;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_time::Timer; use embassy_time::Timer;
use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::pixelcolor::{BinaryColor, Rgb565}; use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::RgbColor; use embedded_graphics::prelude::RgbColor;
use embedded_graphics::{
mono_font::{MonoTextStyle, ascii::FONT_6X10},
prelude::*,
text::Text,
};
use esp_hal::clock::CpuClock; use esp_hal::clock::CpuClock;
use esp_hal::delay::Delay; use esp_hal::delay::Delay;
use esp_hal::gpio::{Input, InputConfig, Pull};
use esp_hal::time::Duration; use esp_hal::time::Duration;
use esp_hal::timer::timg::TimerGroup; use esp_hal::timer::timg::TimerGroup;
use log::error; use log::error;
@@ -39,6 +36,8 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
extern crate alloc; extern crate alloc;
const HEAP_SIZE: usize = 73744;
// This creates a default app-descriptor required by the esp-idf bootloader. // This creates a default app-descriptor required by the esp-idf bootloader.
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description> // For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
esp_bootloader_esp_idf::esp_app_desc!(); esp_bootloader_esp_idf::esp_app_desc!();
@@ -54,53 +53,24 @@ async fn main(spawner: Spawner) {
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config); let peripherals = esp_hal::init(config);
// The following GPIO pins are in use by some feature of the module and should not be used. esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: HEAP_SIZE);
let _ = peripherals.GPIO27;
let _ = peripherals.GPIO28;
let _ = peripherals.GPIO29;
let _ = peripherals.GPIO30;
let _ = peripherals.GPIO31;
let _ = peripherals.GPIO32;
let _ = peripherals.GPIO33;
let _ = peripherals.GPIO34;
esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 73744);
let mut delay = Delay::new();
let button1 = init_navigation_button(peripherals.GPIO38);
let timg0 = TimerGroup::new(peripherals.TIMG0);
let sw_interrupt = let sw_interrupt =
esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0); esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0);
let (mut display, mut oled) = init_dual_displays( let display: &mut PrimaryLcdDisplay = Box::leak(Box::new(init_primary_lcd(
peripherals.SPI2, peripherals.SPI2,
peripherals.GPIO36, // sck peripherals.GPIO36,
peripherals.GPIO35, // mosi peripherals.GPIO35,
peripherals.GPIO37, // miso peripherals.GPIO37,
peripherals.GPIO11, // primary cs peripherals.GPIO11,
peripherals.GPIO13, // oled cs peripherals.GPIO10,
peripherals.GPIO10, // shared reset peripherals.GPIO12,
peripherals.GPIO12, // shared dc )));
&mut delay,
);
setup_wifi(peripherals.WIFI, peripherals.FLASH, &spawner).await; //setup_wifi(peripherals.WIFI, peripherals.FLASH, &spawner).await;
let mut nav_state = NavigationState::new();
oled.clear(BinaryColor::Off).unwrap();
let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On);
Text::new("Hello OLED", Point::new(10, 20), text_style)
.draw(&mut oled)
.unwrap();
oled.flush().unwrap();
let text_style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE);
display.clear_screen(0).unwrap();
Text::new("Hello OLED", Point::new(10, 20), text_style).draw(&mut display).unwrap();
let mut nfc_driver = let mut nfc_driver =
NfcPn532Driver::new(peripherals.I2C0, peripherals.GPIO17, peripherals.GPIO18); NfcPn532Driver::new(peripherals.I2C0, peripherals.GPIO17, peripherals.GPIO18);
@@ -111,7 +81,18 @@ async fn main(spawner: Spawner) {
log::error!("NFC SAM configuration failed"); log::error!("NFC SAM configuration failed");
} }
loop { let mut nav_state = NavigationState::new();
Timer::after_millis(10).await;
} let button_config = InputConfig::default().with_pull(Pull::Up);
let inputs = Inputs {
up: Input::new(peripherals.GPIO38, button_config.clone()),
down: Input::new(peripherals.GPIO39, button_config.clone()),
left: Input::new(peripherals.GPIO40, button_config.clone()),
right: Input::new(peripherals.GPIO41, button_config.clone()),
back: Input::new(peripherals.GPIO42, button_config.clone()),
ok: Input::new(peripherals.GPIO45, button_config.clone()),
};
log::info!("Setup complete, entering main loop");
spawner.spawn(navigation::run(inputs, display).expect("run task failed"));
} }
-3
View File
@@ -1,8 +1,5 @@
pub mod palette; pub mod palette;
pub mod primary_lcd; pub mod primary_lcd;
pub mod secondary_oled; pub mod secondary_oled;
pub mod shared_bus;
pub mod sprite; pub mod sprite;
pub mod tertiary_lcd; pub mod tertiary_lcd;
pub mod views;
+41 -30
View File
@@ -1,43 +1,56 @@
use core::cell::RefCell;
use display_interface_spi::SPIInterface; use display_interface_spi::SPIInterface;
use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::RgbColor; use embedded_graphics::prelude::RgbColor;
use embedded_hal::digital::OutputPin as EhOutputPin; use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_hal_bus::spi::RefCellDevice;
use esp_hal::delay::Delay; use esp_hal::delay::Delay;
use esp_hal::gpio::{Level, Output, OutputConfig, OutputPin}; use esp_hal::gpio::{Level, Output, OutputConfig};
use esp_hal::peripherals::{GPIO10, GPIO11, GPIO12, GPIO35, GPIO36, GPIO37, SPI2};
use esp_hal::spi::{
Mode,
master::{Config, Spi},
};
use esp_hal::time::Rate;
use ili9341::{DisplaySize240x320, Ili9341, Orientation}; use ili9341::{DisplaySize240x320, Ili9341, Orientation};
pub type PrimaryLcdDisplay<'a, BUS, DC, RES> = Ili9341< pub type PrimaryLcdDisplay<'a> = Ili9341<
SPIInterface< SPIInterface<ExclusiveDevice<Spi<'a, esp_hal::Blocking>, Output<'a>, Delay>, Output<'a>>,
RefCellDevice<'a, BUS, Output<'a>, Delay>, Output<'a>,
DC,
>,
RES,
>; >;
pub fn init_primary_lcd_on_bus<'a, BUS, CS, RES, DC>( pub fn init_primary_lcd(
spi_bus: &'a RefCell<BUS>, spi2: SPI2<'static>,
cs: CS, sck: GPIO36<'static>,
reset: RES, mosi: GPIO35<'static>,
dc: DC, miso: GPIO37<'static>,
delay: &mut Delay, cs: GPIO11<'static>,
) -> PrimaryLcdDisplay<'a, BUS, DC, RES> reset: GPIO10<'static>,
where dc: GPIO12<'static>,
BUS: embedded_hal::spi::SpiBus, ) -> PrimaryLcdDisplay<'static> {
CS: OutputPin + 'static, let freq = Rate::from_khz(60_000);
RES: EhOutputPin, log::info!("Display freq: {freq}");
DC: EhOutputPin,
{ let spi_bus = Spi::new(
let cs_pin = Output::new(cs, Level::High, OutputConfig::default()); spi2,
let spi_dev = RefCellDevice::new(spi_bus, cs_pin, *delay).unwrap(); Config::default().with_frequency(freq).with_mode(Mode::_0),
let iface = SPIInterface::new(spi_dev, dc); )
.unwrap()
.with_sck(sck)
.with_mosi(mosi)
.with_miso(miso);
let mut delay = Delay::new();
let cs_main = Output::new(cs, Level::High, OutputConfig::default());
let spi_dev = ExclusiveDevice::new(spi_bus, cs_main, delay).unwrap();
let reset_main = Output::new(reset, Level::High, OutputConfig::default());
let spi_dc = Output::new(dc, Level::High, OutputConfig::default());
let iface = SPIInterface::new(spi_dev, spi_dc);
let mut display = Ili9341::new( let mut display = Ili9341::new(
iface, iface,
reset, reset_main,
delay, &mut delay,
Orientation::Portrait, Orientation::Portrait,
DisplaySize240x320, DisplaySize240x320,
) )
@@ -46,5 +59,3 @@ where
display.clear(Rgb565::BLACK).unwrap(); display.clear(Rgb565::BLACK).unwrap();
display display
} }
+1 -54
View File
@@ -1,54 +1 @@
use core::cell::RefCell; // Secondary OLED module
use display_interface_spi::SPIInterface;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::prelude::*;
use embedded_hal::digital::OutputPin as EhOutputPin;
use embedded_hal_bus::spi::RefCellDevice;
use esp_hal::delay::Delay;
use esp_hal::gpio::{Level, Output, OutputConfig, OutputPin};
use ssd1306::mode::BufferedGraphicsMode;
use ssd1306::prelude::*;
use ssd1306::Ssd1306;
pub type SecondaryOledDisplay<'a, BUS, DC> = Ssd1306<
SPIInterface<
RefCellDevice<'a, BUS, Output<'a>, Delay>,
DC,
>,
DisplaySize128x64,
BufferedGraphicsMode<DisplaySize128x64>,
>;
pub fn init_secondary_oled_on_bus<'a, BUS, CS, RES, DC>(
spi_bus: &'a RefCell<BUS>,
cs: CS,
mut res: RES,
dc: DC,
delay: &mut Delay,
) -> SecondaryOledDisplay<'a, BUS, DC>
where
BUS: embedded_hal::spi::SpiBus,
CS: OutputPin + 'static,
RES: EhOutputPin,
DC: EhOutputPin,
{
let cs_pin = Output::new(cs, Level::High, OutputConfig::default());
let spi_dev = RefCellDevice::new(spi_bus, cs_pin, *delay).unwrap();
let interface = SPIInterface::new(spi_dev, dc);
let mut display = Ssd1306::new(
interface,
DisplaySize128x64,
DisplayRotation::Rotate0,
)
.into_buffered_graphics_mode();
display.reset(&mut res, delay).unwrap();
display.init().unwrap();
display.clear(BinaryColor::Off).unwrap();
display.flush().unwrap();
display
}
-98
View File
@@ -1,98 +0,0 @@
use alloc::boxed::Box;
use core::cell::RefCell;
use embedded_hal::digital::{ErrorType, OutputPin as EhOutputPin, PinState};
use esp_hal::delay::Delay;
use esp_hal::gpio::interconnect::{PeripheralInput, PeripheralOutput};
use esp_hal::gpio::{Level, Output, OutputConfig, OutputPin};
use esp_hal::spi::master::{Config as SpiConfig, Spi};
use esp_hal::spi::Mode;
use esp_hal::time::Rate;
use crate::display::primary_lcd::{init_primary_lcd_on_bus, PrimaryLcdDisplay};
use crate::display::secondary_oled::{init_secondary_oled_on_bus, SecondaryOledDisplay};
pub struct SharedPin<'a>(pub &'a RefCell<Output<'static>>);
impl<'a> ErrorType for SharedPin<'a> {
type Error = core::convert::Infallible;
}
impl<'a> EhOutputPin for SharedPin<'a> {
fn set_low(&mut self) -> Result<(), Self::Error> {
self.0.borrow_mut().set_low();
Ok(())
}
fn set_high(&mut self) -> Result<(), Self::Error> {
self.0.borrow_mut().set_high();
Ok(())
}
fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> {
self.0.borrow_mut().set_state(state);
Ok(())
}
}
pub type DisplaySpiBus = Spi<'static, esp_hal::Blocking>;
pub type DualPrimaryDisplay<'a> = PrimaryLcdDisplay<'a, DisplaySpiBus, SharedPin<'a>, SharedPin<'a>>;
pub type DualSecondaryDisplay<'a> = SecondaryOledDisplay<'a, DisplaySpiBus, SharedPin<'a>>;
pub fn init_dual_displays<SPI, SCK, MOSI, MISO, CS1, CS2, RES, DC>(
spi_peripheral: SPI,
sck: SCK,
mosi: MOSI,
miso: MISO,
cs_primary: CS1,
cs_secondary: CS2,
reset_pin: RES,
dc_pin: DC,
delay: &mut Delay,
) -> (DualPrimaryDisplay<'static>, DualSecondaryDisplay<'static>)
where
SPI: esp_hal::spi::master::Instance + 'static,
SCK: PeripheralOutput<'static>,
MOSI: PeripheralOutput<'static>,
MISO: PeripheralInput<'static>,
CS1: OutputPin + 'static,
CS2: OutputPin + 'static,
RES: OutputPin + 'static,
DC: OutputPin + 'static,
{
let spi = Spi::new(
spi_peripheral,
SpiConfig::default().with_frequency(Rate::from_khz(20_000)).with_mode(Mode::_0),
)
.unwrap()
.with_sck(sck)
.with_mosi(mosi)
.with_miso(miso);
let bus_static: &'static RefCell<DisplaySpiBus> = Box::leak(Box::new(RefCell::new(spi)));
let reset_static: &'static RefCell<Output<'static>> = Box::leak(Box::new(RefCell::new(
Output::new(reset_pin, Level::High, OutputConfig::default()),
)));
let dc_static: &'static RefCell<Output<'static>> = Box::leak(Box::new(RefCell::new(
Output::new(dc_pin, Level::High, OutputConfig::default()),
)));
let primary = init_primary_lcd_on_bus(
bus_static,
cs_primary,
SharedPin(reset_static),
SharedPin(dc_static),
delay,
);
let secondary = init_secondary_oled_on_bus(
bus_static,
cs_secondary,
SharedPin(reset_static),
SharedPin(dc_static),
delay,
);
(primary, secondary)
}
-3
View File
@@ -1,3 +0,0 @@
pub mod card_view;
pub mod menu_view;
pub mod status_bar;
-1
View File
@@ -1 +0,0 @@
// Menu view module
+1
View File
@@ -8,3 +8,4 @@ pub mod drivers;
pub mod navigation; pub mod navigation;
pub mod network; pub mod network;
pub mod storage; pub mod storage;
pub mod views;
+2 -1
View File
@@ -1,2 +1,3 @@
pub mod input; pub mod inputs;
pub mod navigation;
pub mod state; pub mod state;
-15
View File
@@ -1,15 +0,0 @@
use esp_hal::gpio::{Input, InputConfig, Pull};
use esp_hal::peripherals::GPIO38;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NavCommand {
NextCard,
PrevCard,
Select,
ScanTag,
}
pub fn init_navigation_button(pin: GPIO38<'static>) -> Input<'static> {
let button_config = InputConfig::default().with_pull(Pull::Up);
Input::new(pin, button_config)
}
+19
View File
@@ -0,0 +1,19 @@
use esp_hal::gpio::{Input, InputConfig, Pull};
use esp_hal::peripherals::Peripherals;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NavCommand {
NextCard,
PrevCard,
Select,
ScanTag,
}
pub struct Inputs {
pub up: Input<'static>,
pub down: Input<'static>,
pub left: Input<'static>,
pub right: Input<'static>,
pub back: Input<'static>,
pub ok: Input<'static>,
}
+75
View File
@@ -0,0 +1,75 @@
use crate::navigation::state::NavigationState;
use crate::views::view::View;
use crate::{display::primary_lcd::PrimaryLcdDisplay, navigation::inputs::Inputs};
use embassy_futures::select::Either6;
use embassy_futures::select::select6;
use embassy_time::{Duration, Timer};
const DEBOUNCE_DURATION_MILLIS: u64 = 100;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Action {
Up,
Down,
Left,
Right,
Ok,
Back,
}
pub trait Navigable {
fn display(
&self,
display: &mut PrimaryLcdDisplay<'static>,
) -> impl core::future::Future<Output = ()> + Send;
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = View> + Send;
}
#[embassy_executor::task]
pub async fn run(mut inputs: Inputs, display: &'static mut PrimaryLcdDisplay<'static>) {
log::info!("starting navigation");
let mut state = NavigationState::new();
state.screens.last().unwrap().display(display).await;
loop {
let selection = select6(
inputs.up.wait_for_low(),
inputs.down.wait_for_low(),
inputs.left.wait_for_low(),
inputs.right.wait_for_low(),
inputs.ok.wait_for_low(),
inputs.back.wait_for_low(),
)
.await;
let action = match selection {
Either6::First(_) => Action::Up,
Either6::Second(_) => Action::Down,
Either6::Third(_) => Action::Left,
Either6::Fourth(_) => Action::Right,
Either6::Fifth(_) => Action::Ok,
Either6::Sixth(_) => Action::Back,
};
log::info!("Action: {:?}", action);
let screen = match action {
Action::Back => state.back(),
_ => {
state
.screens
.last()
.expect("no screen on stack")
.handle_input(action)
.await
}
};
screen.display(display).await;
state.screens.push(screen);
Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)).await;
}
}
+13 -17
View File
@@ -1,23 +1,16 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)] use crate::views::{main_menu::MainMenu, view::View};
pub enum ScreenMode { use alloc::vec;
CardDetail, use alloc::vec::Vec;
DexGrid,
Settings,
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
pub struct NavigationState { pub struct NavigationState {
pub current_screen: ScreenMode, pub screens: Vec<View>,
pub card_index: usize,
pub use_first_payload: bool,
} }
impl Default for NavigationState { impl Default for NavigationState {
fn default() -> Self { fn default() -> Self {
Self { Self {
current_screen: ScreenMode::CardDetail, screens: vec![View::Main(MainMenu { selected: 0 })],
card_index: 0,
use_first_payload: true,
} }
} }
} }
@@ -27,9 +20,12 @@ impl NavigationState {
Self::default() Self::default()
} }
pub fn toggle_payload(&mut self) -> bool { pub fn back(&mut self) -> View {
let current = self.use_first_payload; let screen = self.screens.pop().unwrap();
self.use_first_payload = !self.use_first_payload; if self.screens.is_empty() {
current log::info!("last screen");
return screen;
}
self.screens.pop().unwrap()
} }
} }
+7
View File
@@ -0,0 +1,7 @@
pub mod card_view;
pub mod main_menu;
pub mod menu_item;
pub mod scan_menu;
pub mod settings_menu;
pub mod status_bar;
pub mod view;
+60
View File
@@ -0,0 +1,60 @@
use core::future;
use crate::display::primary_lcd::PrimaryLcdDisplay;
use crate::views::{menu_item, settings_menu::SettingsMenu, view::View};
use crate::navigation::navigation::{Action, Navigable};
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::RgbColor;
use embedded_graphics_core::draw_target::DrawTarget;
pub const MAX_SELECTED: i32 = 3;
#[derive(Debug, Clone)]
pub struct MainMenu {
pub selected: i32,
}
impl Navigable for MainMenu {
fn display(
&self,
display: &mut PrimaryLcdDisplay<'static>,
) -> impl core::future::Future<Output = ()> + Send {
display.clear(Rgb565::BLACK).unwrap();
menu_item::show(display, "Last card", 0, self.selected);
menu_item::show(display, "Journal", 1, self.selected);
menu_item::show(display, "Settings", 2, self.selected);
core::future::ready(())
}
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = View> + Send {
let new_menu = match input {
Action::Up => {
let new_selected = if (self.selected - 1) < 0 {
MAX_SELECTED - 1
} else {
self.selected - 1
};
View::Main(MainMenu {
selected: new_selected,
})
}
Action::Down => {
let new_selected = self.selected.wrapping_add(1) % MAX_SELECTED;
View::Main(MainMenu {
selected: new_selected,
})
}
Action::Ok => match self.selected {
2 => View::Settings(SettingsMenu { selected: 0 }),
_ => View::Main(self.clone()),
},
_ => View::Main(self.clone()),
};
future::ready(new_menu)
}
}
+33
View File
@@ -0,0 +1,33 @@
use embedded_graphics::mono_font::MonoTextStyle;
use embedded_graphics::mono_font::ascii::FONT_10X20;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::Point;
use embedded_graphics::prelude::RgbColor;
use embedded_graphics::text::Text;
use embedded_graphics::{Drawable, geometry::Size, primitives::Rectangle};
use embedded_graphics_core::draw_target::DrawTarget;
use crate::display::primary_lcd::PrimaryLcdDisplay;
pub fn show<'a>(
display: &mut PrimaryLcdDisplay<'static>,
name: &str,
position: i32,
selected: i32,
) {
let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
let selected_style = MonoTextStyle::new(&FONT_10X20, Rgb565::BLUE);
Text::new(
name,
Point::new(40, 40 + position * 40),
if position == selected {
selected_style
} else {
style
},
)
.draw(display)
.unwrap();
}
+97
View File
@@ -0,0 +1,97 @@
use crate::display::primary_lcd::PrimaryLcdDisplay;
use alloc::format;
use embedded_graphics::Drawable;
use embedded_graphics::geometry::AngleUnit as _;
use embedded_graphics::geometry::Dimensions as _;
use embedded_graphics::geometry::Size;
use embedded_graphics::mono_font::MonoTextStyle;
use embedded_graphics::mono_font::ascii::FONT_10X20;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::Point;
use embedded_graphics::prelude::RgbColor;
use embedded_graphics::primitives::Arc;
use embedded_graphics::primitives::Primitive as _;
use embedded_graphics::primitives::PrimitiveStyleBuilder;
use embedded_graphics::primitives::Rectangle;
use embedded_graphics::primitives::StrokeAlignment;
use embedded_graphics::text::Alignment;
use embedded_graphics::text::Baseline;
use embedded_graphics::text::Text;
use embedded_graphics::text::TextStyleBuilder;
use embedded_graphics_core::draw_target::DrawTarget;
use crate::navigation::navigation::{Action, Navigable};
use crate::views::view::View;
#[derive(Debug, Clone)]
pub struct ScanMenu {
pub progress: u8, // 0..255
}
impl Navigable for ScanMenu {
fn display(
&self,
display: &mut PrimaryLcdDisplay<'static>,
) -> impl core::future::Future<Output = ()> + Send {
let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
display.clear(Rgb565::BLACK).unwrap();
let display_area = display.bounding_box();
Text::new("Scanning...", Point::new(20, 30), style)
.draw(display)
.unwrap();
// Create styles used by the drawing operations.
let arc_stroke = PrimitiveStyleBuilder::new()
.stroke_color(Rgb565::WHITE)
.stroke_width(5)
.stroke_alignment(StrokeAlignment::Inside)
.build();
let character_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
let text_style = TextStyleBuilder::new()
.baseline(Baseline::Middle)
.alignment(Alignment::Center)
.build();
let sweep = self.progress as f32 * 360.0 / 255.0;
let width = display_area.size.width;
let bounding_box =
Rectangle::with_center(display_area.center(), Size::new_equal(4 * width / 5));
// log::info!("bounding_box: {:?}", bounding_box);
// log::info!("display_area: {:?}", display_area);
// Draw an arc with a 5px wide stroke.
Arc::new(
bounding_box.top_left,
bounding_box.size.width,
90.0.deg(),
sweep.deg(),
)
.into_styled(arc_stroke)
.draw(display)
.unwrap();
// Draw centered text.
let text = format!("{:.2}%", 100. * (self.progress as f32) / 255.);
Text::with_text_style(&text, display_area.center(), character_style, text_style)
.draw(display)
.unwrap();
core::future::ready(())
}
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = View> + Send {
async move {
let new_progress = match input {
Action::Up => self.progress.wrapping_add(5),
_ => self.progress,
};
View::Scan(ScanMenu {
progress: new_progress,
})
}
}
}
+31
View File
@@ -0,0 +1,31 @@
use crate::display::primary_lcd::PrimaryLcdDisplay;
use crate::navigation::navigation::{Action, Navigable};
use crate::views::{menu_item, view::View};
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::RgbColor;
use embedded_graphics_core::draw_target::DrawTarget;
pub const MAX_SELECTED: i8 = 2;
#[derive(Debug, Clone)]
pub struct SettingsMenu {
pub selected: i32,
}
impl Navigable for SettingsMenu {
fn display(
&self,
display: &mut PrimaryLcdDisplay<'static>,
) -> impl core::future::Future<Output = ()> + Send {
display.clear(Rgb565::BLACK).unwrap();
menu_item::show(display, "System Inforation", 0, self.selected);
menu_item::show(display, "Wifi Information", 1, self.selected);
core::future::ready(())
}
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = View> + Send {
async move { View::Settings(SettingsMenu { selected: 0 }) }
}
}
+38
View File
@@ -0,0 +1,38 @@
use crate::views::{main_menu::MainMenu, scan_menu::ScanMenu, settings_menu::SettingsMenu};
use crate::navigation::navigation::Navigable;
#[derive(Debug, Clone)]
pub enum View {
Main(MainMenu),
Scan(ScanMenu),
Settings(SettingsMenu),
}
impl Navigable for View {
fn display(
&self,
display: &mut crate::display::primary_lcd::PrimaryLcdDisplay<'static>,
) -> impl core::future::Future<Output = ()> + Send {
async move {
match self {
View::Main(main_menu) => main_menu.display(display).await,
View::Scan(scan_menu) => scan_menu.display(display).await,
View::Settings(settings_menu) => settings_menu.display(display).await,
}
}
}
fn handle_input(
&self,
input: crate::navigation::navigation::Action,
) -> impl core::future::Future<Output = Self> + Send {
async move {
match self {
View::Main(main_menu) => main_menu.handle_input(input).await,
View::Scan(scan_menu) => scan_menu.handle_input(input).await,
View::Settings(settings_menu) => settings_menu.handle_input(input).await,
}
}
}
}