initial commit
commit
789a437590
|
@ -0,0 +1,58 @@
|
||||||
|
q3k's Pullstruder
|
||||||
|
===
|
||||||
|
|
||||||
|
PET bottle recycling machine. Based on the [Recreator3d](http://recreator3d.com/) by Joshua R. Taylor, but with a few twists.
|
||||||
|
|
||||||
|
Work in progress.
|
||||||
|
|
||||||
|
|
||||||
|
Electronics
|
||||||
|
===
|
||||||
|
|
||||||
|
Mainboard is a Melzi 'v5.0' with an ATMega1284P. Reused from a TRONXY X1.
|
||||||
|
|
||||||
|
Schematic of 2.0: https://reprap.org/mediawiki/images/7/7d/Melzi-circuit.png
|
||||||
|
|
||||||
|
EXP connector:
|
||||||
|
----
|
||||||
|
|
||||||
|
PC1 | 1 2 | PA1
|
||||||
|
PC0 | 3 4 | PA2
|
||||||
|
PD3 | 5 6 | PA3
|
||||||
|
PD2 | 7 8 | PA4
|
||||||
|
VCC | 9 10 | GND
|
||||||
|
|
||||||
|
LCD board
|
||||||
|
===
|
||||||
|
|
||||||
|
| EXP Pin | AVR Pin | AVR Function | Screen board function |
|
||||||
|
|---------|---------|--------------|-----------------------|
|
||||||
|
| 1 | PC1 | I2C SDA | LCD D7 |
|
||||||
|
| 2 | PA1 | ADC1 | Button Matrix |
|
||||||
|
| 3 | PC0 | I2C SCL | LCD D6 |
|
||||||
|
| 4 | PA2 | ADC2 | LCD EN |
|
||||||
|
| 5 | PD3 | INT1 | LCD D5 |
|
||||||
|
| 6 | PA3 | ADC3 | LCD RS |
|
||||||
|
| 7 | PD2 | INT0 | LCD D4 |
|
||||||
|
| 8 | PA4 | ADC4 | Unused? |
|
||||||
|
|
||||||
|
Button Matrix
|
||||||
|
---
|
||||||
|
|
||||||
|
Based on a voltage divider between button(s) pressed and a constant pull-up to VCC.
|
||||||
|
|
||||||
|
Resistor to VCC: 4.7k
|
||||||
|
|
||||||
|
| Button | Resistor to GND | Voltage when pressed (VCC=5V) | ADC Value |
|
||||||
|
|--------|-----------------|-------------------------------|-----------|
|
||||||
|
| Left | 470 | 0.45V | 93 |
|
||||||
|
| Down | 1k | 0.87V | 180 |
|
||||||
|
| Menu | 2.2k | 1.6V | 326 |
|
||||||
|
| Right | 4.7k | 2.5V | 512 |
|
||||||
|
| Up | 10k | 3.4V | 697 |
|
||||||
|
|
||||||
|
|
||||||
|
Firmware
|
||||||
|
===
|
||||||
|
|
||||||
|
In progress, written in Rust. Aims to be purpose-specific and not just a repurposed 3D printer control firmware.
|
|
@ -0,0 +1,5 @@
|
||||||
|
[build]
|
||||||
|
target = "avr-specs/avr-atmega1284p.json"
|
||||||
|
|
||||||
|
[unstable]
|
||||||
|
build-std = ["core"]
|
|
@ -0,0 +1,2 @@
|
||||||
|
target
|
||||||
|
old
|
|
@ -0,0 +1,318 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atmega-hal"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/rahix/avr-hal?rev=7b3e82a15e97e657559ec82cf934ba36c38312ec#7b3e82a15e97e657559ec82cf934ba36c38312ec"
|
||||||
|
dependencies = [
|
||||||
|
"avr-device",
|
||||||
|
"avr-hal-generic",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-polyfill"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "avr-device"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84b1e02e846628f283a1c103ef5946224a07092761e4fb91fb93ab794d0b0ada"
|
||||||
|
dependencies = [
|
||||||
|
"avr-device-macros",
|
||||||
|
"bare-metal",
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"vcell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "avr-device-macros"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "817bb402f7da3b9e586d8f2db8a8f3f7d8fdc1562aaa4238a5ed495ebd19fc8f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "avr-hal-generic"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/rahix/avr-hal?rev=7b3e82a15e97e657559ec82cf934ba36c38312ec#7b3e82a15e97e657559ec82cf934ba36c38312ec"
|
||||||
|
dependencies = [
|
||||||
|
"avr-device",
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"embedded-hal",
|
||||||
|
"embedded-storage",
|
||||||
|
"nb 0.1.3",
|
||||||
|
"paste",
|
||||||
|
"rustversion",
|
||||||
|
"ufmt",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bare-metal"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "critical-section"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-hal"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||||
|
dependencies = [
|
||||||
|
"nb 0.1.3",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-storage"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "723dce4e9f25b6e6c5f35628e144794e5b459216ed7da97b7c4b66cdb3fa82ca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hash32"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hd44780-driver"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aab2b13fdeaed7dde9133a57c28b2cbde4a8fc8c3196b5631428aad114857d3a"
|
||||||
|
dependencies = [
|
||||||
|
"embedded-hal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heapless"
|
||||||
|
version = "0.7.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-polyfill",
|
||||||
|
"hash32",
|
||||||
|
"rustc_version",
|
||||||
|
"spin",
|
||||||
|
"stable_deref_trait",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||||
|
dependencies = [
|
||||||
|
"nb 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "panic-halt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-hack"
|
||||||
|
version = "0.5.20+deprecated"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.68"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "recreator3d-q3k-fw"
|
||||||
|
version = "1.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"atmega-hal",
|
||||||
|
"avr-device",
|
||||||
|
"embedded-hal",
|
||||||
|
"hd44780-driver",
|
||||||
|
"heapless",
|
||||||
|
"nb 0.1.3",
|
||||||
|
"panic-halt",
|
||||||
|
"ufmt",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ufmt"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31d3c0c63312dfc9d8e5c71114d617018a19f6058674003c0da29ee8d8036cdd"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-hack",
|
||||||
|
"ufmt-macros",
|
||||||
|
"ufmt-write",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ufmt-macros"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4ab6c92f30c996394a8bd525aef9f03ce01d0d7ac82d81902968057e37dd7d9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-hack",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ufmt-write"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcell"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
|
@ -0,0 +1,27 @@
|
||||||
|
[package]
|
||||||
|
name = "recreator3d-q3k-fw"
|
||||||
|
version = "1.0.0"
|
||||||
|
authors = ["q3k"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
panic-halt = "0.2.0"
|
||||||
|
ufmt = "0.1.0"
|
||||||
|
nb = "0.1.2"
|
||||||
|
embedded-hal = "0.2.3"
|
||||||
|
hd44780-driver = "0"
|
||||||
|
heapless = "0"
|
||||||
|
|
||||||
|
[dependencies.avr-device]
|
||||||
|
version = "0"
|
||||||
|
features = ["rt"]
|
||||||
|
|
||||||
|
[dependencies.atmega-hal]
|
||||||
|
git = "https://github.com/rahix/avr-hal"
|
||||||
|
rev = "7b3e82a15e97e657559ec82cf934ba36c38312ec"
|
||||||
|
features = ["atmega1284p"]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
lto = true
|
||||||
|
opt-level = "z"
|
||||||
|
panic = "abort"
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"arch": "avr",
|
||||||
|
"atomic-cas": false,
|
||||||
|
"cpu": "atmega1284p",
|
||||||
|
"data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8",
|
||||||
|
"eh-frame-header": false,
|
||||||
|
"exe-suffix": ".elf",
|
||||||
|
"executables": true,
|
||||||
|
"late-link-args": {
|
||||||
|
"gcc": [
|
||||||
|
"-lgcc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linker": "avr-gcc",
|
||||||
|
"llvm-target": "avr-unknown-unknown",
|
||||||
|
"max-atomic-width": 8,
|
||||||
|
"no-default-libraries": false,
|
||||||
|
"pre-link-args": {
|
||||||
|
"gcc": [
|
||||||
|
"-mmcu=atmega1284p"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"target-c-int-width": "16",
|
||||||
|
"target-pointer-width": "16"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/4dg5g26sw712f6a9di2zslby8pz9klbd-nixos-system-mimeomia-23.11pre532072.81e8f48ebdec
|
|
@ -0,0 +1,7 @@
|
||||||
|
with import <nixpkgs> {};
|
||||||
|
|
||||||
|
pkgs.mkShell {
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.pkgsCross.avr.buildPackages.gcc
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
use hd44780_driver::HD44780;
|
||||||
|
use embedded_hal::digital::v2::OutputPin;
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use crate::hw::Delay;
|
||||||
|
use crate::logic::State;
|
||||||
|
use crate::view;
|
||||||
|
|
||||||
|
pub struct Display<B: hd44780_driver::bus::DataBus> {
|
||||||
|
lcd: HD44780<B>,
|
||||||
|
delay: Delay,
|
||||||
|
layout: Layout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <RS, EN, D4, D5, D6, D7> Display<hd44780_driver::bus::FourBitBus<RS, EN, D4, D5, D6, D7>>
|
||||||
|
where
|
||||||
|
RS: OutputPin, EN: OutputPin, D4: OutputPin,
|
||||||
|
D5: OutputPin, D6: OutputPin, D7: OutputPin,
|
||||||
|
{
|
||||||
|
pub fn new(rs: RS, en: EN, d4: D4, d5: D5, d6: D6, d7: D7) -> Self
|
||||||
|
{
|
||||||
|
let mut delay = Delay::new();
|
||||||
|
let mut lcd = HD44780::new_4bit(rs, en, d4, d5, d6, d7, &mut delay).unwrap();
|
||||||
|
lcd.reset(&mut delay).ok();
|
||||||
|
lcd.clear(&mut delay).ok();
|
||||||
|
lcd.set_display_mode(hd44780_driver::display_mode::DisplayMode {
|
||||||
|
cursor_visibility: hd44780_driver::Cursor::Invisible,
|
||||||
|
cursor_blink: hd44780_driver::CursorBlink::Off,
|
||||||
|
display: hd44780_driver::Display::On,
|
||||||
|
}, &mut delay).ok();
|
||||||
|
Display {
|
||||||
|
lcd,
|
||||||
|
delay,
|
||||||
|
layout: Layout::Empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <B: hd44780_driver::bus::DataBus> Display<B> {
|
||||||
|
fn pos(&self, x: u8, y: u8) -> u8 {
|
||||||
|
match y {
|
||||||
|
0 => x,
|
||||||
|
1 => x + 64,
|
||||||
|
2 => x + 20,
|
||||||
|
3 => x + 84,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn write_str_at(&mut self, x: usize, y: usize, s: &str) {
|
||||||
|
if x > 19 || y > 3 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let mut len = 20 - x;
|
||||||
|
if len as usize > s.len() {
|
||||||
|
len = s.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = x as u8;
|
||||||
|
let y = y as u8;
|
||||||
|
self.lcd.set_cursor_pos(self.pos(x, y), &mut self.delay).ok();
|
||||||
|
let len = len as usize;
|
||||||
|
self.lcd.write_str(&s[..len], &mut self.delay).ok();
|
||||||
|
}
|
||||||
|
pub fn write(&mut self, l: Layout) {
|
||||||
|
match l {
|
||||||
|
Layout::Empty => {
|
||||||
|
if let Layout::Empty = self.layout {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.lcd.clear(&mut self.delay).ok();
|
||||||
|
},
|
||||||
|
Layout::Splash => {
|
||||||
|
self.lcd.clear(&mut self.delay).ok();
|
||||||
|
self.write_str_at((20 - SPLASH_1.len()) / 2, 1, SPLASH_1);
|
||||||
|
self.write_str_at((20 - SPLASH_2.len()) / 2, 2, SPLASH_2);
|
||||||
|
},
|
||||||
|
Layout::Status(ref cur) => {
|
||||||
|
let mut temperature_changed = true;
|
||||||
|
let mut time_left_changed = true;
|
||||||
|
let mut state_changed = true;
|
||||||
|
let mut speed_changed = true;
|
||||||
|
if let Layout::Status(ref prev) = &self.layout {
|
||||||
|
temperature_changed = prev.temperature != cur.temperature;
|
||||||
|
time_left_changed = prev.time_left != cur.time_left;
|
||||||
|
state_changed = prev.state != cur.state;
|
||||||
|
speed_changed = prev.speed != cur.speed;
|
||||||
|
} else {
|
||||||
|
self.lcd.clear(&mut self.delay).ok();
|
||||||
|
self.write_str_at(0, 0, " State");
|
||||||
|
self.write_str_at(0, 1, "Temperature");
|
||||||
|
self.write_str_at(0, 2, " Speed");
|
||||||
|
self.write_str_at(0, 3, " Time Left");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut s: heapless::String<16> = heapless::String::new();
|
||||||
|
|
||||||
|
if state_changed {
|
||||||
|
let s = match cur.state {
|
||||||
|
State::Idle => "Idle ",
|
||||||
|
State::Preheating => "Heating",
|
||||||
|
State::Running => "Running",
|
||||||
|
};
|
||||||
|
self.write_str_at(12, 0, s);
|
||||||
|
}
|
||||||
|
if temperature_changed {
|
||||||
|
s.clear();
|
||||||
|
write!(s, "{}.{}C", cur.temperature / 10, cur.temperature % 10).ok();
|
||||||
|
while s.len() < 8 {
|
||||||
|
s.push(' ').ok();
|
||||||
|
}
|
||||||
|
self.write_str_at(12, 1, &s);
|
||||||
|
}
|
||||||
|
if speed_changed {
|
||||||
|
s.clear();
|
||||||
|
write!(s, "{}mm/s", cur.speed).ok();
|
||||||
|
while s.len() < 8 {
|
||||||
|
s.push(' ').ok();
|
||||||
|
}
|
||||||
|
self.write_str_at(12, 2, &s);
|
||||||
|
}
|
||||||
|
if time_left_changed {
|
||||||
|
s.clear();
|
||||||
|
let h = cur.time_left / 3600;
|
||||||
|
let m = (cur.time_left / 60) % 60;
|
||||||
|
let ss = cur.time_left % 60;
|
||||||
|
write!(s, "{:02}:{:02}:{:02}", h, m, ss).ok();
|
||||||
|
while s.len() < 8 {
|
||||||
|
s.push(' ').ok();
|
||||||
|
}
|
||||||
|
self.write_str_at(12, 3, &s);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Layout::Menu(ref cur) => {
|
||||||
|
let redraw_options = match &self.layout {
|
||||||
|
Layout::Menu(LayoutMenu { name, .. }) => *name != cur.name,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
let redraw_cursor = match &self.layout {
|
||||||
|
Layout::Menu(LayoutMenu { pos, .. }) => *pos != cur.pos,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if redraw_options {
|
||||||
|
self.lcd.clear(&mut self.delay).ok();
|
||||||
|
for (i, option) in cur.options.iter().enumerate() {
|
||||||
|
self.write_str_at(1, i, option.label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if redraw_cursor {
|
||||||
|
for (i, _) in cur.options.iter().enumerate() {
|
||||||
|
if i == cur.pos {
|
||||||
|
self.write_str_at(0, i, ">");
|
||||||
|
} else {
|
||||||
|
self.write_str_at(0, i, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.layout = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LayoutStatus {
|
||||||
|
pub temperature: u16,
|
||||||
|
pub time_left: u32,
|
||||||
|
pub state: State,
|
||||||
|
pub speed: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LayoutMenu {
|
||||||
|
pub name: view::ViewID,
|
||||||
|
pub pos: usize,
|
||||||
|
pub options: &'static [view::MenuOption],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Layout {
|
||||||
|
Empty,
|
||||||
|
Splash,
|
||||||
|
Status(LayoutStatus),
|
||||||
|
Menu(LayoutMenu),
|
||||||
|
}
|
||||||
|
|
||||||
|
const SPLASH_1: &'static str = "q3k's pullstruder";
|
||||||
|
const SPLASH_2: &'static str = "2023/10/07";
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
use embedded_hal::blocking::delay::DelayMs;
|
||||||
|
|
||||||
|
pub type Clock = atmega_hal::clock::MHz16;
|
||||||
|
pub type Delay = atmega_hal::delay::Delay<Clock>;
|
||||||
|
|
||||||
|
pub fn delay_ms(ms: u16) {
|
||||||
|
Delay::new().delay_ms(ms)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
#[derive(Eq, PartialEq, Clone, Copy)]
|
||||||
|
pub enum Key {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Select,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(button_adc_val: u16) -> Option<Key> {
|
||||||
|
match button_adc_val {
|
||||||
|
80..=100 => Some(Key::Left),
|
||||||
|
170..=190 => Some(Key::Down),
|
||||||
|
320..=330 => Some(Key::Select),
|
||||||
|
500..=520 => Some(Key::Right),
|
||||||
|
690..=710 => Some(Key::Up),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum State {
|
||||||
|
Idle,
|
||||||
|
Preheating,
|
||||||
|
Running,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum UserRequest {
|
||||||
|
Start,
|
||||||
|
Adjust {
|
||||||
|
speed: Option<u16>,
|
||||||
|
temperature: Option<u16>,
|
||||||
|
time: Option<u32>,
|
||||||
|
},
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Input {
|
||||||
|
pub timestamp: u32,
|
||||||
|
pub temperature: u16,
|
||||||
|
pub request: Option<UserRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Controller {
|
||||||
|
pub state: State,
|
||||||
|
deadline: u32,
|
||||||
|
configured_seconds: u32,
|
||||||
|
last_timestamp: u32,
|
||||||
|
pub speed: u16,
|
||||||
|
pub temperature: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Controller {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
state: State::Idle,
|
||||||
|
deadline: 0,
|
||||||
|
configured_seconds: 3600,
|
||||||
|
last_timestamp: 0,
|
||||||
|
speed: 300,
|
||||||
|
temperature: 2137,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn time_left(&self) -> u32 {
|
||||||
|
match self.state {
|
||||||
|
State::Running => {
|
||||||
|
if self.last_timestamp > self.deadline {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
self.deadline - self.last_timestamp
|
||||||
|
},
|
||||||
|
_ => self.configured_seconds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process(&mut self, i: &Input) {
|
||||||
|
self.last_timestamp = i.timestamp;
|
||||||
|
match self.state {
|
||||||
|
State::Idle => self.process_idle(i),
|
||||||
|
State::Preheating => self.process_preheating(i),
|
||||||
|
State::Running => self.process_running(i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_adjust(&mut self, speed: Option<u16>, temperature: Option<u16>, time: Option<u32>) {
|
||||||
|
if let Some(speed) = speed {
|
||||||
|
self.speed = speed;
|
||||||
|
}
|
||||||
|
if let Some(temperature) = temperature {
|
||||||
|
self.temperature = temperature;
|
||||||
|
}
|
||||||
|
if let Some(time) = time {
|
||||||
|
self.configured_seconds = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_idle(&mut self, i: &Input) {
|
||||||
|
if let Some(req) = &i.request {
|
||||||
|
match req {
|
||||||
|
UserRequest::Start => {
|
||||||
|
self.deadline = i.timestamp + self.configured_seconds;
|
||||||
|
self.state = State::Preheating;
|
||||||
|
},
|
||||||
|
UserRequest::Adjust { speed, temperature, time } => {
|
||||||
|
self.apply_adjust(speed.clone(), temperature.clone(), time.clone());
|
||||||
|
},
|
||||||
|
UserRequest::Stop => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_preheating(&mut self, i: &Input) {
|
||||||
|
if let Some(req) = &i.request {
|
||||||
|
match req {
|
||||||
|
UserRequest::Start {..} => {},
|
||||||
|
UserRequest::Adjust { speed, temperature, time } => {
|
||||||
|
self.apply_adjust(speed.clone(), temperature.clone(), time.clone());
|
||||||
|
},
|
||||||
|
UserRequest::Stop => {
|
||||||
|
self.state = State::Idle;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_running(&mut self, i: &Input) {
|
||||||
|
if let Some(req) = &i.request {
|
||||||
|
match req {
|
||||||
|
UserRequest::Start {..} => {},
|
||||||
|
UserRequest::Adjust { speed, temperature, time } => {
|
||||||
|
self.apply_adjust(speed.clone(), temperature.clone(), time.clone());
|
||||||
|
},
|
||||||
|
UserRequest::Stop => {
|
||||||
|
self.state = State::Idle;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(abi_avr_interrupt)]
|
||||||
|
|
||||||
|
use panic_halt as _;
|
||||||
|
|
||||||
|
mod key;
|
||||||
|
mod view;
|
||||||
|
mod display;
|
||||||
|
mod logic;
|
||||||
|
mod hw;
|
||||||
|
|
||||||
|
/// Seconds elapsed since startup. Overflows after 136 years of uptime.
|
||||||
|
static mut TICKS_SEC: u32 = 0;
|
||||||
|
|
||||||
|
#[avr_device::interrupt(atmega1284p)]
|
||||||
|
fn TIMER1_COMPA() {
|
||||||
|
unsafe {
|
||||||
|
TICKS_SEC += 1;
|
||||||
|
if TICKS_SEC == 0 {
|
||||||
|
panic!("have you been running this non-stop for 136 years????");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ticks_sec() -> u32 {
|
||||||
|
let v = unsafe {
|
||||||
|
TICKS_SEC
|
||||||
|
};
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[avr_device::entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let dp = atmega_hal::Peripherals::take().unwrap();
|
||||||
|
let pins = atmega_hal::pins!(dp);
|
||||||
|
|
||||||
|
|
||||||
|
let mut led = pins.pa4.into_output().downgrade();
|
||||||
|
|
||||||
|
let mut display = display::Display::new(
|
||||||
|
pins.pa3.into_output(), // RS
|
||||||
|
pins.pa2.into_output(), // EN
|
||||||
|
pins.pd2.into_output(), // D4
|
||||||
|
pins.pd3.into_output(), // D5
|
||||||
|
pins.pc0.into_output(), // D6
|
||||||
|
pins.pc1.into_output(), // D7
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut adc = atmega_hal::Adc::<hw::Clock>::new(dp.ADC, Default::default());
|
||||||
|
let menu_pin = pins.pa1.into_analog_input(&mut adc);
|
||||||
|
|
||||||
|
// Configure TMR1 at 1Hz.
|
||||||
|
let tmr1 = dp.TC1;
|
||||||
|
tmr1.tccr1a.write(|w| w.wgm1().bits(0b00));
|
||||||
|
tmr1.tccr1b.write(|w| w.cs1().prescale_1024().wgm1().bits(0b01));
|
||||||
|
tmr1.ocr1a.write(|w| w.bits(15624));
|
||||||
|
tmr1.timsk1.write(|w| w.ocie1a().set_bit());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
avr_device::interrupt::enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
display.write(display::Layout::Splash);
|
||||||
|
hw::delay_ms(1000);
|
||||||
|
|
||||||
|
let mut ctrl = logic::Controller::new();
|
||||||
|
let mut menu = view::ViewManager::new();
|
||||||
|
let mut prev_key: Option<key::Key> = None;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let ticks = ticks_sec();
|
||||||
|
|
||||||
|
// UI
|
||||||
|
let key = key::parse(adc.read_blocking(&menu_pin));
|
||||||
|
let mut menu_input = view::ViewInput {
|
||||||
|
key: None,
|
||||||
|
};
|
||||||
|
if key != prev_key {
|
||||||
|
menu_input.key = key;
|
||||||
|
};
|
||||||
|
prev_key = key;
|
||||||
|
let req = menu.process(&menu_input);
|
||||||
|
display.write(menu.layout(&ctrl));
|
||||||
|
|
||||||
|
// Logic
|
||||||
|
let input = logic::Input {
|
||||||
|
timestamp: ticks,
|
||||||
|
temperature: 2137,
|
||||||
|
request: req,
|
||||||
|
};
|
||||||
|
ctrl.process(&input);
|
||||||
|
led.toggle();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/// Convert from ADC value to decidegrees.
|
||||||
|
fn convert(adc: u16) -> u16 {
|
||||||
|
// The thermistor is connected via a resistor divider:
|
||||||
|
//
|
||||||
|
// VCC <---/\/\/\---+---/\/\/\----> GND
|
||||||
|
// 4.7k | NTC
|
||||||
|
// V ADC
|
||||||
|
//
|
||||||
|
// If we express V_SUP in arbitrary ADC units (0-1023), then we can
|
||||||
|
// calculate the resistance as a function of ADC value:
|
||||||
|
//
|
||||||
|
// R = 4700 / ((1024 / ADC) - 1)
|
||||||
|
|
||||||
|
// Clamp to safe value. This prevents division by zero.
|
||||||
|
let adc = if adc >= 1024 { 1024 } else { adc};
|
||||||
|
let adc = if adc < 1 { 1 } else { adc };
|
||||||
|
let r = 4700 / ((1024 / adc) - 1);
|
|
@ -0,0 +1,159 @@
|
||||||
|
use crate::key::Key;
|
||||||
|
use crate::logic::{Controller, UserRequest};
|
||||||
|
use crate::display::{Layout, LayoutStatus, LayoutMenu};
|
||||||
|
|
||||||
|
pub struct ViewInput {
|
||||||
|
pub key: Option<Key>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum ViewID {
|
||||||
|
Status,
|
||||||
|
Main,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MenuAction {
|
||||||
|
goto_view: Option<ViewID>,
|
||||||
|
logic_request: Option<UserRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MenuAction {
|
||||||
|
fn nothing() -> Self {
|
||||||
|
Self {
|
||||||
|
goto_view: None,
|
||||||
|
logic_request: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn just_goto_view(vid: ViewID) -> Self {
|
||||||
|
Self {
|
||||||
|
goto_view: Some(vid),
|
||||||
|
logic_request: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn just_logic_request(req: UserRequest) -> Self {
|
||||||
|
Self {
|
||||||
|
goto_view: None,
|
||||||
|
logic_request: Some(req),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait View {
|
||||||
|
fn layout(&self, controller: &Controller) -> Layout;
|
||||||
|
fn process(&mut self, input: &ViewInput) -> MenuAction;
|
||||||
|
fn enter(&mut self) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StatusView;
|
||||||
|
|
||||||
|
impl View for StatusView {
|
||||||
|
fn layout(&self, controller: &Controller) -> Layout {
|
||||||
|
Layout::Status(LayoutStatus {
|
||||||
|
temperature: controller.temperature,
|
||||||
|
time_left: controller.time_left(),
|
||||||
|
state: controller.state,
|
||||||
|
speed: controller.speed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn process(&mut self, input: &ViewInput) -> MenuAction {
|
||||||
|
if input.key.is_some() {
|
||||||
|
return MenuAction::just_goto_view(ViewID::Main);
|
||||||
|
}
|
||||||
|
return MenuAction::nothing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Menu {
|
||||||
|
id: ViewID,
|
||||||
|
pos: usize,
|
||||||
|
options: &'static [MenuOption],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MenuOption {
|
||||||
|
pub label: &'static str,
|
||||||
|
action: MenuAction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for Menu {
|
||||||
|
fn layout(&self, _controller: &Controller) -> Layout {
|
||||||
|
Layout::Menu(LayoutMenu {
|
||||||
|
name: self.id,
|
||||||
|
pos: self.pos,
|
||||||
|
options: self.options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process(&mut self, input: &ViewInput) -> MenuAction{
|
||||||
|
match input.key {
|
||||||
|
Some(Key::Up) => { if self.pos > 0 { self.pos -= 1; } },
|
||||||
|
Some(Key::Down) => { if self.pos < self.options.len()-1 { self.pos += 1; } },
|
||||||
|
Some(Key::Select) => { return self.options[self.pos].action.clone() },
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
return MenuAction::nothing();
|
||||||
|
}
|
||||||
|
fn enter(&mut self) {
|
||||||
|
self.pos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ViewManager {
|
||||||
|
status: StatusView,
|
||||||
|
main: Menu,
|
||||||
|
cur: ViewID,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
status: StatusView,
|
||||||
|
main: Menu {
|
||||||
|
id: ViewID::Main,
|
||||||
|
pos: 0,
|
||||||
|
options: &[
|
||||||
|
MenuOption {
|
||||||
|
label: "Back",
|
||||||
|
action: MenuAction {
|
||||||
|
goto_view: Some(ViewID::Status),
|
||||||
|
logic_request: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MenuOption {
|
||||||
|
label: "Start",
|
||||||
|
action: MenuAction {
|
||||||
|
goto_view: Some(ViewID::Status),
|
||||||
|
logic_request: Some(UserRequest::Start),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
cur: ViewID::Status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn layout(&self, controller: &Controller) -> Layout {
|
||||||
|
match self.cur {
|
||||||
|
ViewID::Status => self.status.layout(controller),
|
||||||
|
ViewID::Main => self.main.layout(controller),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process(&mut self, input: &ViewInput) -> Option<UserRequest> {
|
||||||
|
let new = match self.cur {
|
||||||
|
ViewID::Status => self.status.process(input),
|
||||||
|
ViewID::Main => self.main.process(input),
|
||||||
|
};
|
||||||
|
if let Some(id) = new.goto_view {
|
||||||
|
self.cur = id;
|
||||||
|
match self.cur {
|
||||||
|
ViewID::Status => self.status.enter(),
|
||||||
|
ViewID::Main => self.main.enter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new.logic_request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue