Initial Commit
This commit is contained in:
14
.cargo/config.toml
Normal file
14
.cargo/config.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[target.xtensa-esp32-none-elf]
|
||||
runner = "espflash flash --monitor --chip esp32"
|
||||
|
||||
[env]
|
||||
|
||||
[build]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-nostartfiles",
|
||||
]
|
||||
|
||||
target = "xtensa-esp32-none-elf"
|
||||
|
||||
[unstable]
|
||||
build-std = ["alloc", "core"]
|
||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# RustRover
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"rust-lang.rust-analyzer",
|
||||
"tamasfe.even-better-toml",
|
||||
"fill-labs.dependi"
|
||||
]
|
||||
}
|
||||
13
.vscode/settings.json
vendored
Normal file
13
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"rust-analyzer.cargo.allTargets": false,
|
||||
"rust-analyzer.cargo.target": "xtensa-esp32-none-elf",
|
||||
"rust-analyzer.server.extraEnv": {
|
||||
"RUSTUP_TOOLCHAIN": "stable"
|
||||
},
|
||||
"rust-analyzer.check.extraEnv": {
|
||||
"RUSTUP_TOOLCHAIN": "esp"
|
||||
},
|
||||
"rust-analyzer.cargo.extraEnv": {
|
||||
"RUSTUP_TOOLCHAIN": "esp"
|
||||
},
|
||||
}
|
||||
1231
Cargo.lock
generated
Normal file
1231
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
Cargo.toml
Normal file
42
Cargo.toml
Normal file
@@ -0,0 +1,42 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "mtgcount-rs"
|
||||
version = "0.1.0"
|
||||
|
||||
[[bin]]
|
||||
name = "mtgcount-rs"
|
||||
path = "./src/bin/main.rs"
|
||||
|
||||
[dependencies]
|
||||
critical-section = "1.2.0"
|
||||
display-interface = "0.5.0"
|
||||
embedded-graphics = "0.8.1"
|
||||
embedded-hal = "1.0.0"
|
||||
embedded-hal-bus = "0.3.0"
|
||||
esp-alloc = "0.7.0"
|
||||
esp-backtrace = { version = "0.15.1", features = [
|
||||
"esp32",
|
||||
"exception-handler",
|
||||
"panic-handler",
|
||||
"println",
|
||||
] }
|
||||
esp-hal = { version = "1.0.0-beta.0", features = ["esp32", "unstable"] }
|
||||
esp-println = { version = "0.13.0", features = ["esp32"] }
|
||||
esp32 = "0.38.0"
|
||||
micromath = "2.1.0"
|
||||
mipidsi = "0.9.0"
|
||||
u8g2-fonts = "0.7.1"
|
||||
|
||||
[profile.dev]
|
||||
# Rust debug is too slow.
|
||||
# For debug builds always builds with some optimization
|
||||
opt-level = "s"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1 # LLVM can perform better optimizations using a single thread
|
||||
debug = 2
|
||||
debug-assertions = false
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 's'
|
||||
overflow-checks = false
|
||||
40
build.rs
Normal file
40
build.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
fn main() {
|
||||
linker_be_nice();
|
||||
// make sure linkall.x is the last linker script (otherwise might cause problems with flip-link)
|
||||
println!("cargo:rustc-link-arg=-Tlinkall.x");
|
||||
}
|
||||
|
||||
fn linker_be_nice() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let kind = &args[1];
|
||||
let what = &args[2];
|
||||
|
||||
match kind.as_str() {
|
||||
"undefined-symbol" => match what.as_str() {
|
||||
"_defmt_timestamp" => {
|
||||
eprintln!();
|
||||
eprintln!("💡 `defmt` not found - make sure `defmt.x` is added as a linker script and you have included `use defmt_rtt as _;`");
|
||||
eprintln!();
|
||||
}
|
||||
"_stack_start" => {
|
||||
eprintln!();
|
||||
eprintln!("💡 Is the linker script `linkall.x` missing?");
|
||||
eprintln!();
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
// we don't have anything helpful for "missing-lib" yet
|
||||
_ => {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-arg=-Wl,--error-handling-script={}",
|
||||
std::env::current_exe().unwrap().display()
|
||||
);
|
||||
}
|
||||
2
rust-toolchain.toml
Normal file
2
rust-toolchain.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "esp"
|
||||
216
src/bin/main.rs
Normal file
216
src/bin/main.rs
Normal file
@@ -0,0 +1,216 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embedded_graphics::framebuffer::{buffer_size, Framebuffer};
|
||||
use embedded_graphics::pixelcolor::raw::LittleEndian;
|
||||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use embedded_graphics::draw_target::DrawTarget;
|
||||
use embedded_graphics::image::ImageDrawable;
|
||||
|
||||
use esp_backtrace as _;
|
||||
|
||||
use esp_hal::clock::CpuClock;
|
||||
use esp_hal::gpio::{self, InputConfig, OutputConfig};
|
||||
use esp_hal::rtc_cntl::sleep::{GpioWakeupSource, RtcSleepConfig};
|
||||
use esp_hal::rtc_cntl::Rtc;
|
||||
use esp_hal::main;
|
||||
|
||||
use esp_println::println;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use mtgcount_rs::{self, TP_GESTURE, TP_X, TP_Y};
|
||||
|
||||
#[main]
|
||||
fn main() -> ! {
|
||||
// generator version: 0.3.1
|
||||
println!("Startup init");
|
||||
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
||||
let peripherals = esp_hal::init(config);
|
||||
|
||||
let pins = mtgcount_rs::init::UsedPins::init(peripherals);
|
||||
|
||||
let mut buffer = [0_u8;256];
|
||||
|
||||
//set clocks;
|
||||
|
||||
let mut iic = pins.init_iic();
|
||||
let mut display = pins.init_display(&mut buffer);
|
||||
let mut framebuf: Framebuffer<Rgb565, _, LittleEndian, 240, 240, {buffer_size::<Rgb565>(240, 240)}> = Framebuffer::new();
|
||||
//let mut bgbuf: Framebuffer<Rgb565, _, LittleEndian, 240, 240, {buffer_size::<Rgb565>(240, 240)}> = Framebuffer::new();
|
||||
|
||||
|
||||
//start bl
|
||||
println!("Begin backlight setup");
|
||||
println!("Start Low Power backlight config");
|
||||
let low_power = unsafe {esp_hal::peripherals::LPWR::steal()};
|
||||
low_power.register_block().clk_conf().modify(|_,w| w.ck8m_force_pd().clear_bit());
|
||||
low_power.register_block().clk_conf().modify(|_,w| w.ck8m_force_pu().set_bit());
|
||||
low_power.register_block().clk_conf().modify(|_,w| w.enb_ck8m().clear_bit());
|
||||
low_power.register_block().clk_conf().modify(|_,w| w.dig_clk8m_en().set_bit());
|
||||
|
||||
println!("Init Backlight peripherals");
|
||||
let (led, bl, rtcio) = pins.init_backlight();
|
||||
|
||||
let mux = unsafe{esp_hal::peripherals::IO_MUX::steal()};
|
||||
mux.register_block().gpio32().modify(|_,w| w.mcu_oe().set_bit());
|
||||
rtcio.register_block().enable().modify(|_,w| unsafe{w.enable().bits(0x80_00_00)});
|
||||
rtcio.register_block().xtal_32k_pad().modify(|_,w| w.x32n_hold().clear_bit());
|
||||
rtcio.register_block().xtal_32k_pad().modify(|_,w| unsafe{w.x32n_fun_sel().bits(0)});
|
||||
rtcio.register_block().xtal_32k_pad().modify(|_,w| w.x32n_slp_oe().set_bit());
|
||||
|
||||
let _ledc = esp_hal::ledc::Ledc::new(led);
|
||||
//ledc.set_global_slow_clock(esp_hal::ledc::LSGlobalClkSource::APBClk);
|
||||
|
||||
println!("Set apb_clk_sel");
|
||||
let test = unsafe {esp_hal::peripherals::LEDC::steal()};
|
||||
test.register_block().conf().write(|w| w.apb_clk_sel().clear_bit());
|
||||
test.register_block().lstimer(0).conf().modify(|_,w| w.para_up().set_bit());
|
||||
|
||||
//let mut lstimer0 = ledc.timer::<LowSpeed>(esp_hal::ledc::timer::Number::Timer0);
|
||||
//lstimer0.configure(esp_hal::ledc::timer::config::Config {
|
||||
// duty: esp_hal::ledc::timer::config::Duty::Duty5Bit,
|
||||
// clock_source: esp_hal::ledc::timer::LSClockSource::APBClk,
|
||||
// frequency: Rate::from_khz(2),
|
||||
//}).unwrap();
|
||||
|
||||
let precision = 1 << 8u64;
|
||||
let divisor = ((8_000_000u64) << 8) / 1_000 / precision;
|
||||
println!("Set up lstimer0");
|
||||
println!("Lstimer divisor is:{}", divisor);
|
||||
|
||||
test.register_block().lstimer(0).conf().modify(|_,w| unsafe {
|
||||
w.tick_sel().bit(true);
|
||||
w.rst().clear_bit();
|
||||
w.pause().clear_bit();
|
||||
w.div_num().bits(divisor as u32);
|
||||
w.duty_res().bits(8)
|
||||
});
|
||||
test.register_block().lstimer(0).conf().modify(|_,w| w.para_up().set_bit());
|
||||
|
||||
//let mut channel0 = ledc.channel(esp_hal::ledc::channel::Number::Channel0, bl);
|
||||
//channel0.configure(esp_hal::ledc::channel::config::Config {
|
||||
// timer: &lstimer0,
|
||||
// duty_pct: 50,
|
||||
// pin_config: esp_hal::ledc::channel::config::PinConfig::PushPull,
|
||||
//}).unwrap();
|
||||
|
||||
let mut duty_percent = 100;
|
||||
let duty_range = 2u32.pow(8);
|
||||
let mut duty_value = (duty_range * duty_percent) / 100;
|
||||
println!("Setup channel0");
|
||||
|
||||
test.register_block().lsch(0).duty().write(|w| unsafe {
|
||||
w.duty().bits(duty_value<<4)
|
||||
});
|
||||
test.register_block().lsch(0).conf1().write(|w| unsafe {
|
||||
w.duty_start().set_bit();
|
||||
w.duty_inc().set_bit();
|
||||
w.duty_num().bits(0x1);
|
||||
w.duty_cycle().bits(0x1);
|
||||
w.duty_scale().bits(0x0)
|
||||
});
|
||||
test.register_block().lsch(0).conf0().modify(|_,w| w.para_up().set_bit());
|
||||
|
||||
println!("Configure output signal");
|
||||
let newbl: esp_hal::gpio::interconnect::OutputSignal = bl.into();
|
||||
println!("line1");
|
||||
newbl.apply_output_config(&OutputConfig::default().with_drive_mode(gpio::DriveMode::PushPull));
|
||||
println!("line2");
|
||||
newbl.set_output_enable(true);
|
||||
println!("Completed output signal config");
|
||||
|
||||
test.register_block().lsch(0).hpoint().write(|w| unsafe {
|
||||
w.hpoint().bits(0x0)
|
||||
});
|
||||
println!("Completed hpoint set");
|
||||
|
||||
test.register_block().lsch(0).conf0().modify(|_,w| unsafe {
|
||||
w.sig_out_en().set_bit().timer_sel().bits(0)
|
||||
});
|
||||
println!("Completed signal output enable");
|
||||
test.register_block().lsch(0).conf1().write(|w| unsafe {
|
||||
w.duty_start().set_bit();
|
||||
w.duty_inc().set_bit();
|
||||
w.duty_num().bits(0x1);
|
||||
w.duty_cycle().bits(0x1);
|
||||
w.duty_scale().bits(0x0)
|
||||
});
|
||||
test.register_block().lsch(0).conf0().modify(|_,w| w.para_up().set_bit());
|
||||
println!("Completed channel0 reupdate");
|
||||
|
||||
let signal = esp_hal::gpio::OutputSignal::LEDC_LS_SIG0;
|
||||
signal.connect_to(&newbl);
|
||||
println!("End Backlight setup");
|
||||
//end bl
|
||||
|
||||
let mut read_buffer = [0_u8;1];
|
||||
|
||||
esp_alloc::heap_allocator!(size: 16 * 1024);
|
||||
|
||||
let pinconf = InputConfig::default();
|
||||
let irq = pins.irq();
|
||||
let _wake_pin = esp_hal::gpio::Input::new(irq, pinconf).wakeup_enable(true,esp_hal::gpio::WakeEvent::LowLevel).unwrap();
|
||||
|
||||
let waker = GpioWakeupSource::new();
|
||||
println!("Start Sleep Config setup");
|
||||
let mut rtc_control = Rtc::new(low_power);
|
||||
println!("line1");
|
||||
let mut rtc_config: RtcSleepConfig = RtcSleepConfig::default();
|
||||
println!("line2");
|
||||
rtc_config.set_int_8m_pd_en(false);
|
||||
println!("Finish Sleep Config setup");
|
||||
|
||||
//let loop_delay = esp_hal::delay::Delay::new();
|
||||
|
||||
let mut gesture;
|
||||
let mut x;
|
||||
let mut y;
|
||||
|
||||
println!("Systemstate init");
|
||||
let mut state = mtgcount_rs::state::SystemState::new();
|
||||
println!("screen: {:?}", state.screen);
|
||||
|
||||
framebuf.clear(state.settings.color_scheme.get_color(&mtgcount_rs::display::ColorType::Background)).unwrap();
|
||||
display.clear(state.settings.color_scheme.get_color(&mtgcount_rs::display::ColorType::Background)).unwrap();
|
||||
mtgcount_rs::display::draw_screen(&state, &mut framebuf);
|
||||
framebuf.as_image().draw(&mut display).unwrap();
|
||||
|
||||
loop {
|
||||
//println!("Enterd Loop");
|
||||
iic.write_read(0x15, &[TP_GESTURE], &mut read_buffer).expect("Failed to do iic");
|
||||
gesture = read_buffer[0];
|
||||
iic.write_read(0x15, &[TP_X], &mut read_buffer).expect("Failed to do iic");
|
||||
x = read_buffer[0];
|
||||
iic.write_read(0x15, &[TP_Y], &mut read_buffer).expect("Failed to do iic");
|
||||
y = read_buffer[0];
|
||||
|
||||
mtgcount_rs::touch::get_touch_action(x as f32, y as f32, gesture, &mut state);
|
||||
|
||||
duty_percent = state.settings.brightness as u32;
|
||||
duty_value = (duty_range * duty_percent) / 100;
|
||||
|
||||
//println!("Duty Percent: {}%", duty_percent);
|
||||
|
||||
test.register_block().lsch(0).duty().write(|w| unsafe {w.duty().bits(duty_value<<4)});
|
||||
|
||||
test.register_block().lsch(0).conf1().write(|w| unsafe {
|
||||
w.duty_start().set_bit();
|
||||
w.duty_inc().set_bit();
|
||||
w.duty_num().bits(0x1);
|
||||
w.duty_cycle().bits(0x1);
|
||||
w.duty_scale().bits(0x0)
|
||||
});
|
||||
|
||||
test.register_block().lsch(0).conf0().modify(|_,w| w.para_up().set_bit());
|
||||
|
||||
mtgcount_rs::display::draw_screen(&state, &mut framebuf);
|
||||
framebuf.as_image().draw(&mut display).unwrap();
|
||||
|
||||
framebuf.clear(state.settings.color_scheme.get_color(&mtgcount_rs::display::ColorType::Background)).unwrap();
|
||||
|
||||
rtc_control.sleep(&rtc_config,&[&waker]);
|
||||
|
||||
}
|
||||
// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0-beta.0/examples/src/bin
|
||||
}
|
||||
205
src/bin/mini_ulp.s
Normal file
205
src/bin/mini_ulp.s
Normal file
@@ -0,0 +1,205 @@
|
||||
REG_WR 0x103, 0x17, 0x17, 1
|
||||
REG_WR 0x123, 0x18, 0x18, 0
|
||||
REG_WR 0x123, 0x11, 0x11, 1
|
||||
REG_WR 0x123, 0x06, 0x06, 1
|
||||
entry:
|
||||
MOVE R0, dutycycle //6
|
||||
LD R0, R0, 0 //8
|
||||
LSH R1, R0, 4 //6
|
||||
ADD R0, R0, R1 //6
|
||||
ADD R0, R0, 10 //6
|
||||
JUMP R0 //4
|
||||
//36
|
||||
0x0a:
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 12 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 717 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 12 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 717 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 12 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 717 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 12 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 677 //6
|
||||
JUMP entry //4
|
||||
0x22:
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 84 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 645 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 84 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 645 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 84 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 645 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 84 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 605 //6
|
||||
JUMP entry //4
|
||||
0x3a:
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 156 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 573 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 156 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 573 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 156 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 573 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 156 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 533 //6
|
||||
JUMP entry //4
|
||||
0x52:
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 228 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 501 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 228 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 501 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 228 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 501 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 228 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 461 //6
|
||||
JUMP entry //4
|
||||
0x6a:
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 300 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 429 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 300 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 429 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 300 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 429 //6
|
||||
REG_WR 0x101, 0x17, 0x17, 1 //12
|
||||
WAIT 300 //6
|
||||
REG_WR 0x102, 0x17, 0x17, 1 //12
|
||||
WAIT 389 //6
|
||||
JUMP entry //4
|
||||
0x82:
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 357
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 372
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 357
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 372
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 357
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 372
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 357
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 332
|
||||
JUMP entry
|
||||
0x9a:
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 285
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 444
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 285
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 444
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 285
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 444
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 285
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 404
|
||||
JUMP entry
|
||||
0xb2:
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 213
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 516
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 213
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 516
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 213
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 516
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 213
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 476
|
||||
JUMP entry
|
||||
0xca:
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 141
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 606
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 141
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 606
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 141
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 606
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 141
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 566
|
||||
JUMP entry
|
||||
0xe2:
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 69
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 660
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 69
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 660
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 69
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 660
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 69
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 620
|
||||
JUMP entry
|
||||
0xfa:
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 12
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 1482
|
||||
REG_WR 0x102, 0x17, 0x17, 1
|
||||
WAIT 12
|
||||
REG_WR 0x101, 0x17, 0x17, 1
|
||||
WAIT 1442
|
||||
JUMP entry
|
||||
|
||||
dutycycle:
|
||||
.long 0
|
||||
1551
src/bin/ulp_program.s
Normal file
1551
src/bin/ulp_program.s
Normal file
File diff suppressed because it is too large
Load Diff
447
src/display.rs
Normal file
447
src/display.rs
Normal file
@@ -0,0 +1,447 @@
|
||||
use embedded_graphics::prelude::{Angle, DrawTarget, Point, Primitive, RgbColor};
|
||||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use embedded_graphics::Drawable;
|
||||
|
||||
use u8g2_fonts::{fonts::{u8g2_font_7x13_tr, u8g2_font_9x15B_tr, u8g2_font_logisoso24_tr, u8g2_font_logisoso42_tr, u8g2_font_open_iconic_all_2x_t, u8g2_font_open_iconic_check_4x_t}, FontRenderer};
|
||||
|
||||
use micromath::F32Ext;
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::{vec::Vec, string::ToString};
|
||||
use embedded_graphics::primitives::PrimitiveStyle;
|
||||
|
||||
use crate::state::{MainScreenItem, Screen, SystemState};
|
||||
use crate::setting_screen::{setting_screen, setting_scroll};
|
||||
|
||||
pub const LARGE_FONT:FontRenderer = FontRenderer::new::<u8g2_font_logisoso42_tr>();
|
||||
pub const MED_PLUS_FONT:FontRenderer = FontRenderer::new::<u8g2_font_logisoso24_tr>();
|
||||
pub const MED_FONT:FontRenderer = FontRenderer::new::<u8g2_font_9x15B_tr>();
|
||||
pub const SMALL_FONT:FontRenderer = FontRenderer::new::<u8g2_font_7x13_tr>();
|
||||
pub const ICONS:FontRenderer = FontRenderer::new::<u8g2_font_open_iconic_all_2x_t>();
|
||||
pub const CHECK:FontRenderer = FontRenderer::new::<u8g2_font_open_iconic_check_4x_t>();
|
||||
|
||||
const LIGHTCREAM: Rgb565 = Rgb565::new(31, 62, 26);
|
||||
const LIGHTBLUE: Rgb565 = Rgb565::new(21, 55, 30);
|
||||
const DARKBLUE: Rgb565 = Rgb565::new(1, 27, 22);
|
||||
const LIGHTGREY: Rgb565 = Rgb565::new(25, 48, 23);
|
||||
const DARKGREY: Rgb565 = Rgb565::new(8, 16, 8);
|
||||
const LIGHTRED: Rgb565 = Rgb565::new(30, 42, 17);
|
||||
const LIGHTGREEN: Rgb565 = Rgb565::new(19,52,21);
|
||||
|
||||
|
||||
const ALMOSTBLACK: Rgb565 = Rgb565::new(3, 6, 3);
|
||||
|
||||
|
||||
|
||||
|
||||
const CENTER: Point = Point::new(120, 120);
|
||||
|
||||
#[derive(Debug,Clone, Copy)]
|
||||
pub enum ColorType {
|
||||
Primary,
|
||||
Secondary,
|
||||
Tertiary,
|
||||
Background
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone, Copy)]
|
||||
pub enum ColorScheme {
|
||||
Light,
|
||||
Dark,
|
||||
White,
|
||||
Blue,
|
||||
Black,
|
||||
Red,
|
||||
Green,
|
||||
Azorius,
|
||||
Dimir,
|
||||
}
|
||||
|
||||
impl ColorScheme {
|
||||
pub fn get_color(&self, color_type: &ColorType) -> Rgb565 {
|
||||
match self {
|
||||
Self::Light => {
|
||||
match color_type {
|
||||
ColorType::Primary => Rgb565::BLACK,
|
||||
ColorType::Secondary => Rgb565::BLACK,
|
||||
ColorType::Tertiary => Rgb565::BLACK,
|
||||
ColorType::Background => Rgb565::WHITE,
|
||||
}
|
||||
},
|
||||
Self::Dark => {
|
||||
match color_type {
|
||||
ColorType::Primary => Rgb565::WHITE,
|
||||
ColorType::Secondary => ALMOSTBLACK,
|
||||
ColorType::Tertiary => Rgb565::WHITE,
|
||||
ColorType::Background => Rgb565::BLACK,
|
||||
}
|
||||
},
|
||||
Self::White => {
|
||||
match color_type {
|
||||
ColorType::Primary => Rgb565::BLACK,
|
||||
ColorType::Secondary => Rgb565::BLACK,
|
||||
ColorType::Tertiary => Rgb565::BLACK,
|
||||
ColorType::Background => LIGHTCREAM,
|
||||
}
|
||||
},
|
||||
Self::Blue => {
|
||||
match color_type {
|
||||
ColorType::Primary => Rgb565::BLACK,
|
||||
ColorType::Secondary => DARKBLUE,
|
||||
ColorType::Tertiary => Rgb565::BLACK,
|
||||
ColorType::Background => LIGHTBLUE
|
||||
}
|
||||
},
|
||||
Self::Black => {
|
||||
match color_type {
|
||||
ColorType::Primary => Rgb565::BLACK,
|
||||
ColorType::Secondary => Rgb565::BLACK,
|
||||
ColorType::Tertiary => Rgb565::BLACK,
|
||||
ColorType::Background => LIGHTGREY,
|
||||
}
|
||||
},
|
||||
Self::Red => {
|
||||
match color_type {
|
||||
ColorType::Primary => Rgb565::BLACK,
|
||||
ColorType::Secondary => Rgb565::BLACK,
|
||||
ColorType::Tertiary => Rgb565::BLACK,
|
||||
ColorType::Background => LIGHTRED,
|
||||
}
|
||||
},
|
||||
Self::Green => {
|
||||
match color_type {
|
||||
ColorType::Primary => Rgb565::BLACK,
|
||||
ColorType::Secondary => Rgb565::BLACK,
|
||||
ColorType::Tertiary => Rgb565::BLACK,
|
||||
ColorType::Background => LIGHTGREEN,
|
||||
}
|
||||
},
|
||||
Self::Azorius => {
|
||||
match color_type {
|
||||
ColorType::Primary => DARKBLUE,
|
||||
ColorType::Secondary => DARKBLUE,
|
||||
ColorType::Tertiary => DARKBLUE,
|
||||
ColorType::Background => LIGHTCREAM,
|
||||
}
|
||||
},
|
||||
Self::Dimir => {
|
||||
match color_type {
|
||||
ColorType::Primary => DARKGREY,
|
||||
ColorType::Secondary => DARKGREY,
|
||||
ColorType::Tertiary => DARKGREY,
|
||||
ColorType::Background => LIGHTBLUE,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
ColorScheme::Light => "Light",
|
||||
ColorScheme::Dark => "Dark",
|
||||
ColorScheme::White => "White",
|
||||
ColorScheme::Blue => "Blue",
|
||||
ColorScheme::Black => "Black",
|
||||
ColorScheme::Red => "Red",
|
||||
ColorScheme::Green => "Green",
|
||||
ColorScheme::Azorius => "Azorius",
|
||||
ColorScheme::Dimir => "Dmir",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inc(self) -> Self {
|
||||
let mut tmp:u8 = self.into();
|
||||
tmp += 1;
|
||||
if tmp > 8 {
|
||||
tmp = 0
|
||||
}
|
||||
Self::from(tmp)
|
||||
}
|
||||
|
||||
pub fn dec(self) -> Self {
|
||||
let tmp:u8 = self.into();
|
||||
let tmp = tmp.checked_sub(1);
|
||||
let tmp = match tmp {
|
||||
Some(u) => u,
|
||||
None => 8,
|
||||
};
|
||||
Self::from(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
pub const COLORSCHEMES: usize = 9;
|
||||
|
||||
impl From<u8> for ColorScheme {
|
||||
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Self::Dark,
|
||||
2 => Self::White,
|
||||
3 => Self::Blue,
|
||||
4 => Self::Black,
|
||||
5 => Self::Red,
|
||||
6 => Self::Green,
|
||||
7 => Self::Azorius,
|
||||
8 => Self::Dimir,
|
||||
_ => Self::Light,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for ColorScheme {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
ColorScheme::Light => 0,
|
||||
ColorScheme::Dark => 1,
|
||||
ColorScheme::White => 2,
|
||||
ColorScheme::Blue => 3,
|
||||
ColorScheme::Black => 4,
|
||||
ColorScheme::Red => 5,
|
||||
ColorScheme::Green => 6,
|
||||
ColorScheme::Azorius => 7,
|
||||
ColorScheme::Dimir => 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_screen<A: DrawTarget<Color = Rgb565>>(ctx: &SystemState, target: &mut A) -> () {
|
||||
|
||||
let primary = ctx.settings.color_scheme.get_color(&ColorType::Primary);
|
||||
let background = ctx.settings.color_scheme.get_color(&ColorType::Background);
|
||||
|
||||
_ = target.clear(background);
|
||||
|
||||
match &ctx.screen {
|
||||
Screen::Main(selection) => {
|
||||
|
||||
let style = PrimitiveStyle::with_stroke(ctx.settings.color_scheme.get_color(&ColorType::Secondary), 3);
|
||||
|
||||
let bottom_count =
|
||||
ctx.settings.show_cmd_tax as u8 +
|
||||
ctx.settings.show_energy as u8 +
|
||||
ctx.settings.show_experience as u8 +
|
||||
ctx.settings.show_infect as u8 +
|
||||
ctx.settings.show_tickets as u8;
|
||||
|
||||
if (ctx.settings.opponenets > 0) & (ctx.settings.opponenets < 7) {
|
||||
let top_positions = ctx.positions.get_top_list(ctx.settings.opponenets);
|
||||
|
||||
for (pos, dmg) in top_positions.iter().zip(ctx.game.cmd_dmg) {
|
||||
|
||||
_ = SMALL_FONT.render_aligned(
|
||||
dmg.as_string_horizontal().as_str(),
|
||||
pos.position,
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
}
|
||||
|
||||
let start = (ctx.settings.opponenets as f32 * 15.)-90.;
|
||||
let sweep = ctx.settings.opponenets as f32 * -30.;
|
||||
let arc = embedded_graphics::primitives::Arc::with_center(CENTER, 160, Angle::from_degrees(start), Angle::from_degrees(sweep));
|
||||
|
||||
//println!("start: {}", start);
|
||||
|
||||
let _ = arc.into_styled(style).draw(target);
|
||||
|
||||
for i in 0..= ctx.settings.opponenets {
|
||||
let angle = (start + 90. - (30.*(i as f32))) * crate::DEG_TO_RAD;
|
||||
let (sin_t, cos_t) = angle.sin_cos();
|
||||
//println!("angle: {}, sin: {}, cos: {}", angle, sin_t, cos_t);
|
||||
|
||||
let line1 = Point::new(
|
||||
((79. * sin_t)+120.) as i32,
|
||||
((-79. * cos_t)+120.) as i32
|
||||
);
|
||||
let line2 = Point::new(
|
||||
((125. * sin_t)+120.) as i32,
|
||||
((-125. * cos_t)+120.) as i32
|
||||
);
|
||||
|
||||
let drawline = embedded_graphics::primitives::Line::new(line1, line2);
|
||||
|
||||
//println!("{:?}", drawline);
|
||||
let _ = drawline.into_styled(style).draw(target);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if bottom_count != 0 {
|
||||
let bottom_positions = ctx.positions.get_bottom_list(bottom_count);
|
||||
|
||||
let mut bottom_vec = Vec::with_capacity(bottom_count as usize);
|
||||
|
||||
if ctx.settings.show_cmd_tax {
|
||||
let tmp = ctx.game.cmd_tax.as_string_horizontal();
|
||||
bottom_vec.push((tmp, '\u{0092}'));
|
||||
}
|
||||
if ctx.settings.show_energy {
|
||||
let tmp = ctx.game.energy.to_string();
|
||||
bottom_vec.push((tmp,'\u{0060}'));
|
||||
}
|
||||
if ctx.settings.show_experience {
|
||||
let tmp = ctx.game.experience.to_string();
|
||||
bottom_vec.push((tmp,'\u{0103}'));
|
||||
}
|
||||
if ctx.settings.show_tickets {
|
||||
let tmp = ctx.game.tickets.to_string();
|
||||
bottom_vec.push((tmp, '\u{0106}'));
|
||||
}
|
||||
if ctx.settings.show_infect {
|
||||
let tmp = ctx.game.infect.to_string();
|
||||
bottom_vec.push((tmp,'\u{005c}'));
|
||||
}
|
||||
|
||||
for (pos, content) in bottom_positions.iter().zip(bottom_vec) {
|
||||
|
||||
_ = SMALL_FONT.render_aligned(
|
||||
content.0.as_str(),
|
||||
pos.position,
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target);
|
||||
|
||||
_ = ICONS.render_aligned(
|
||||
content.1,
|
||||
pos.position,
|
||||
u8g2_fonts::types::VerticalPosition::Top,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target);
|
||||
}
|
||||
|
||||
let start = (bottom_count as f32 * 15.)+90.;
|
||||
let sweep = bottom_count as f32 * -30.;
|
||||
let arc = embedded_graphics::primitives::Arc::with_center(CENTER, 160, Angle::from_degrees(start), Angle::from_degrees(sweep));
|
||||
let _ = arc.into_styled(style).draw(target);
|
||||
|
||||
for i in 0..=bottom_count {
|
||||
let angle = (start + 90. - (30.*(i as f32))) * crate::DEG_TO_RAD;
|
||||
let (sin_t, cos_t) = angle.sin_cos();
|
||||
//println!("angle: {}, sin: {}, cos: {}", angle, sin_t, cos_t);
|
||||
|
||||
let line1 = Point::new(
|
||||
((79. * sin_t)+120.) as i32,
|
||||
((-79. * cos_t)+120.) as i32
|
||||
);
|
||||
let line2 = Point::new(
|
||||
((125. * sin_t)+120.) as i32,
|
||||
((-125. * cos_t)+120.) as i32
|
||||
);
|
||||
|
||||
let drawline = embedded_graphics::primitives::Line::new(line1, line2);
|
||||
|
||||
//println!("{:?}", drawline);
|
||||
let _ = drawline.into_styled(style).draw(target);
|
||||
}
|
||||
}
|
||||
|
||||
let center_item = match selection {
|
||||
MainScreenItem::Dmg1 => (ctx.game.cmd_dmg[0].as_string_horizontal(),"Opponent 1"),
|
||||
MainScreenItem::Dmg2 => (ctx.game.cmd_dmg[1].as_string_horizontal(),"Opponent 2"),
|
||||
MainScreenItem::Dmg3 => (ctx.game.cmd_dmg[2].as_string_horizontal(),"Opponent 3"),
|
||||
MainScreenItem::Dmg4 => (ctx.game.cmd_dmg[3].as_string_horizontal(),"Opponent 4"),
|
||||
MainScreenItem::Dmg5 => (ctx.game.cmd_dmg[4].as_string_horizontal(),"Opponent 5"),
|
||||
MainScreenItem::Dmg6 => (ctx.game.cmd_dmg[5].as_string_horizontal(),"Opponent 6"),
|
||||
MainScreenItem::Tax => (ctx.game.cmd_tax.as_string_horizontal(),"Commander Tax"),
|
||||
MainScreenItem::Energy => (ctx.game.energy.to_string(),"Energy"),
|
||||
MainScreenItem::Experience => (ctx.game.experience.to_string(),"Experience"),
|
||||
MainScreenItem::Tickets => (ctx.game.tickets.to_string(),"Tickets"),
|
||||
MainScreenItem::Poison => (ctx.game.infect.to_string(),"Poison"),
|
||||
_ => (ctx.game.life.to_string(),"Life"),
|
||||
};
|
||||
|
||||
let _ = LARGE_FONT.render_aligned(
|
||||
center_item.0.as_str(),
|
||||
ctx.positions.center,
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
|
||||
let _ = SMALL_FONT.render_aligned(
|
||||
center_item.1,
|
||||
Point::new(120, 150),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
|
||||
let content = match selection {
|
||||
MainScreenItem::Dmg1 => Some(0),
|
||||
MainScreenItem::Dmg2 => Some(1),
|
||||
MainScreenItem::Dmg3 => Some(2),
|
||||
MainScreenItem::Dmg4 => Some(3),
|
||||
MainScreenItem::Dmg5 => Some(4),
|
||||
MainScreenItem::Dmg6 => Some(5),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(pos) = content {
|
||||
let content = if ctx.game.cmd_dmg[pos].is_partner {
|
||||
"0"
|
||||
} else {
|
||||
"0|0"
|
||||
};
|
||||
|
||||
let _ = SMALL_FONT.render_aligned(
|
||||
content,
|
||||
Point { x: 120, y: 170 },
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
} else if *selection == MainScreenItem::Tax {
|
||||
let content = if ctx.game.cmd_tax.is_partner {
|
||||
"0"
|
||||
} else {
|
||||
"0|0"
|
||||
};
|
||||
|
||||
let _ = SMALL_FONT.render_aligned(
|
||||
content,
|
||||
Point { x: 120, y: 170 },
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
}
|
||||
}
|
||||
Screen::Settings(selection) => {
|
||||
setting_scroll(ctx, selection, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
opponents 1-6
|
||||
|
||||
life total
|
||||
|
||||
tax
|
||||
energy
|
||||
experience
|
||||
tix
|
||||
poison
|
||||
|
||||
opponents
|
||||
starting life
|
||||
new game
|
||||
colors
|
||||
brightness
|
||||
|
||||
show tax
|
||||
show energy
|
||||
show experience
|
||||
show tickets
|
||||
show poison
|
||||
*/
|
||||
115
src/init.rs
Normal file
115
src/init.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use core::cell::Cell;
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use esp_hal::{delay::Delay, gpio::Output, i2c::master::I2c, peripherals::*, spi::master::Spi, time::Rate, Blocking};
|
||||
use mipidsi::{interface::SpiInterface, models::GC9A01};
|
||||
|
||||
pub struct UsedPins<'a> {
|
||||
sda: Cell<Option<GPIO21<'a>>>,
|
||||
scl: Cell<Option<GPIO22<'a>>>,
|
||||
irq: Cell<Option<GPIO19<'a>>>,
|
||||
tp_rst: Cell<Option<GPIO4<'a>>>,
|
||||
|
||||
sclk: Cell<Option<GPIO14<'a>>>,
|
||||
mosi: Cell<Option<GPIO15<'a>>>,
|
||||
cs: Cell<Option<GPIO5<'a>>>,
|
||||
dc: Cell<Option<GPIO27<'a>>>,
|
||||
reset: Cell<Option<GPIO33<'a>>>,
|
||||
bl: Cell<Option<GPIO32<'a>>>,
|
||||
|
||||
iic: Cell<Option<I2C0<'a>>>,
|
||||
spi: Cell<Option<SPI2<'a>>>,
|
||||
lpwr: Cell<Option<LPWR<'a>>>,
|
||||
ledc: Cell<Option<LEDC<'a>>>,
|
||||
//dport: Cell<Option<DPORT<'a>>>,
|
||||
io_mux: Cell<Option<RTC_IO<'a>>>,
|
||||
//rtc_io: Cell<Option<LPWR<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a> UsedPins<'a> {
|
||||
|
||||
pub fn init(peripherals: esp_hal::peripherals::Peripherals) -> Self {
|
||||
|
||||
UsedPins {
|
||||
sda: Cell::new(Some(peripherals.GPIO21)),
|
||||
scl: Cell::new(Some(peripherals.GPIO22)),
|
||||
irq: Cell::new(Some(peripherals.GPIO19)),
|
||||
tp_rst: Cell::new(Some(peripherals.GPIO4)),
|
||||
|
||||
sclk: Cell::new(Some(peripherals.GPIO14)),
|
||||
mosi: Cell::new(Some(peripherals.GPIO15)),
|
||||
cs: Cell::new(Some(peripherals.GPIO5)),
|
||||
dc: Cell::new(Some(peripherals.GPIO27)),
|
||||
reset: Cell::new(Some(peripherals.GPIO33)),
|
||||
bl: Cell::new(Some(peripherals.GPIO32)),
|
||||
|
||||
iic: Cell::new(Some(peripherals.I2C0)),
|
||||
spi: Cell::new(Some(peripherals.SPI2)),
|
||||
lpwr: Cell::new(Some(peripherals.LPWR)),
|
||||
|
||||
ledc: Cell::new(Some(peripherals.LEDC)),
|
||||
//dport: Cell::new(Some(peripherals.DPORT)),
|
||||
io_mux: Cell::new(Some(peripherals.RTC_IO)),
|
||||
//rtc_io: Cell::new(Some(peripherals.LPWR)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn irq(&self) -> GPIO19 {
|
||||
let irq = self.irq.replace(None).unwrap();
|
||||
irq
|
||||
}
|
||||
|
||||
pub fn tp_rst(&self) -> GPIO4 {
|
||||
let tp_rst = self.tp_rst.replace(None).unwrap();
|
||||
tp_rst
|
||||
}
|
||||
|
||||
pub fn get_lpwr(&self) -> LPWR<'a> {
|
||||
let pin = self.lpwr.replace(None).unwrap();
|
||||
pin
|
||||
}
|
||||
|
||||
pub fn init_backlight(&self) -> (LEDC<'a>, GPIO32<'a>, RTC_IO<'a>) {
|
||||
let bl = self.bl.replace(None).unwrap();
|
||||
let ledc = self.ledc.replace(None).unwrap();
|
||||
//let rtc_io = self.rtc_io.replace(None).unwrap();
|
||||
let io_mux = self.io_mux.replace(None).unwrap();
|
||||
|
||||
(ledc, bl, io_mux)
|
||||
}
|
||||
|
||||
pub fn init_iic(&self) -> I2c<'_, Blocking> {
|
||||
let mut iic = I2c::new(self.iic.replace(None).unwrap(), esp_hal::i2c::master::Config::default()).unwrap()
|
||||
.with_sda(self.sda.replace(None).unwrap())
|
||||
.with_scl(self.scl.replace(None).unwrap());
|
||||
|
||||
iic.write(0x15, &[0xFA_u8, 0b00010001]).expect("Failed to set irqctl");
|
||||
|
||||
iic
|
||||
}
|
||||
|
||||
pub fn init_display(&'a self, buffer: &'a mut [u8]) -> mipidsi::Display<SpiInterface<'a, ExclusiveDevice<esp_hal::spi::master::Spi<'a, Blocking>, Output<'a>, Delay>, Output<'a>>, GC9A01, Output<'a>> {
|
||||
let spi = Spi::new(
|
||||
self.spi.replace(None).unwrap(),
|
||||
esp_hal::spi::master::Config::default()
|
||||
.with_frequency(Rate::from_mhz(40))
|
||||
).unwrap()
|
||||
.with_sck(self.sclk.replace(None).unwrap())
|
||||
.with_mosi(self.mosi.replace(None).unwrap());
|
||||
|
||||
let cs_pin = esp_hal::gpio::Output::new(self.cs.replace(None).unwrap(), esp_hal::gpio::Level::Low, esp_hal::gpio::OutputConfig::default());
|
||||
let dc_pin = esp_hal::gpio::Output::new(self.dc.replace(None).unwrap(), esp_hal::gpio::Level::High, esp_hal::gpio::OutputConfig::default());
|
||||
let rs_pin = esp_hal::gpio::Output::new(self.reset.replace(None).unwrap(), esp_hal::gpio::Level::High, esp_hal::gpio::OutputConfig::default().with_pull(esp_hal::gpio::Pull::Up));
|
||||
let mut delay = esp_hal::delay::Delay::new();
|
||||
|
||||
let spi_dev = ExclusiveDevice::new(spi, cs_pin, delay).unwrap();
|
||||
let mipi_interface = mipidsi::interface::SpiInterface::new(spi_dev, dc_pin, buffer);
|
||||
let display = mipidsi::Builder::new(GC9A01, mipi_interface)
|
||||
.reset_pin(rs_pin)
|
||||
.invert_colors(mipidsi::options::ColorInversion::Inverted)
|
||||
.color_order(mipidsi::options::ColorOrder::Bgr)
|
||||
.init(&mut delay).unwrap();
|
||||
|
||||
display
|
||||
}
|
||||
}
|
||||
|
||||
15
src/lib.rs
Normal file
15
src/lib.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#![no_std]
|
||||
|
||||
pub mod init;
|
||||
pub mod state;
|
||||
pub mod display;
|
||||
pub mod touch;
|
||||
pub mod setting_screen;
|
||||
|
||||
pub const IIC_ADDRESS: u8 = 0x15_u8;
|
||||
pub const TP_GESTURE: u8 = 0x01_u8;
|
||||
pub const TP_X: u8 = 0x04_u8;
|
||||
pub const TP_Y: u8 = 0x06_u8;
|
||||
|
||||
pub const RAD_TO_DEG: f32 = 57.2957795;
|
||||
pub const DEG_TO_RAD: f32 = 0.017453293;
|
||||
492
src/setting_screen.rs
Normal file
492
src/setting_screen.rs
Normal file
@@ -0,0 +1,492 @@
|
||||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use embedded_graphics::prelude::{DrawTarget, Point, Primitive, RgbColor, Size};
|
||||
use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
|
||||
use embedded_graphics::Drawable;
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::{vec::Vec, string::ToString};
|
||||
use u8g2_fonts::types::{FontColor, HorizontalAlignment, VerticalPosition};
|
||||
|
||||
use crate::state::{SettingScreenEntry, SettingScreenItem, SystemState};
|
||||
use crate::display::{CHECK, SMALL_FONT, MED_FONT, MED_PLUS_FONT};
|
||||
|
||||
use crate::display::{ColorScheme, COLORSCHEMES};
|
||||
|
||||
pub(crate) fn setting_screen<A>(ctx: &SystemState, selection: &SettingScreenItem, target: &mut A) -> ()
|
||||
where A: DrawTarget<Color = Rgb565>
|
||||
{
|
||||
let primary = ctx.settings.color_scheme.get_color(&crate::display::ColorType::Primary);
|
||||
let background = ctx.settings.color_scheme.get_color(&crate::display::ColorType::Background);
|
||||
|
||||
let top_count = 5;
|
||||
let bottom_count = 5;
|
||||
|
||||
let top_positions = &ctx.positions.top_setting_locations;
|
||||
let bottom_positions = &ctx.positions.bottom_setting_locations;
|
||||
|
||||
let mut top_vec = Vec::with_capacity(top_count as usize);
|
||||
|
||||
top_vec.push("Opponents");
|
||||
top_vec.push("Starting\nLife");
|
||||
top_vec.push("New Game");
|
||||
top_vec.push("Color\nScheme");
|
||||
top_vec.push("Brightness");
|
||||
|
||||
let mut bottom_vec = Vec::with_capacity(bottom_count as usize);
|
||||
|
||||
bottom_vec.push("Commander\nTax");
|
||||
bottom_vec.push("Energy");
|
||||
bottom_vec.push("Exp");
|
||||
bottom_vec.push("Tix");
|
||||
bottom_vec.push("Poison");
|
||||
|
||||
for (pos, content) in top_positions.iter().chain(bottom_positions.iter()).zip(top_vec.into_iter().chain(bottom_vec.into_iter())) {
|
||||
_ = SMALL_FONT.render_aligned(
|
||||
content,
|
||||
pos.position,
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target);
|
||||
}
|
||||
|
||||
match selection.entry {
|
||||
SettingScreenEntry::NewGame => {
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Start\nNew Game.",
|
||||
ctx.positions.center,
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::Opponents => {
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
ctx.settings.opponenets.to_string().as_str(),
|
||||
ctx.positions.center,
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::StartingLife => {
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
ctx.settings.starting_life.to_string().as_str(),
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::Colors => {
|
||||
let current_scheme_number: u8 = ctx.settings.color_scheme.into();
|
||||
let prev_scheme_number;
|
||||
let check_sub = current_scheme_number.checked_sub(1);
|
||||
if let Some(p) = check_sub {
|
||||
prev_scheme_number = p;
|
||||
} else {
|
||||
prev_scheme_number = COLORSCHEMES as u8 - 1;
|
||||
}
|
||||
let prev_scheme: ColorScheme = prev_scheme_number.into();
|
||||
|
||||
let next_scheme_number;
|
||||
let check_add = current_scheme_number + 1;
|
||||
if check_add >= COLORSCHEMES as u8 {
|
||||
next_scheme_number = 0;
|
||||
} else {
|
||||
next_scheme_number = check_add;
|
||||
}
|
||||
let next_scheme: ColorScheme = next_scheme_number.into();
|
||||
|
||||
let _ = MED_FONT.render_aligned(
|
||||
prev_scheme.as_str(),
|
||||
Point::new(120, 80),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
ctx.settings.color_scheme.as_str(),
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
|
||||
let _ = MED_FONT.render_aligned(
|
||||
next_scheme.as_str(),
|
||||
Point::new(120, 160),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::Brightness => {
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
ctx.settings.brightness.as_str(),
|
||||
ctx.positions.center,
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::ShowTax => {
|
||||
//Yes/No rendering
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nCommand Tax?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_cmd_tax));
|
||||
},
|
||||
SettingScreenEntry::ShowEnergy => {
|
||||
//Yes/No rendering
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nEnergy?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_energy));
|
||||
},
|
||||
SettingScreenEntry::ShowExperience => {
|
||||
//Yes/No rendering
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nExperience?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_experience));
|
||||
},
|
||||
SettingScreenEntry::ShowTickets => {
|
||||
//Yes/No rendering
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nTickets?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_tickets));
|
||||
},
|
||||
SettingScreenEntry::ShowPoison => {
|
||||
//Yes/No rendering
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nPoison?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_infect));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn draw_yes_no<A: DrawTarget<Color = Rgb565>>(primary: Rgb565, background: Rgb565, display: &mut A, selected: Option<bool>) -> () {
|
||||
let yes_color;
|
||||
let no_color;
|
||||
let rect_point;
|
||||
|
||||
if let Some(sel) = selected {
|
||||
if sel {
|
||||
yes_color = background;
|
||||
no_color = primary;
|
||||
rect_point = Point::new(75, 125);
|
||||
} else {
|
||||
yes_color = primary;
|
||||
no_color = background;
|
||||
rect_point = Point::new(120,125);
|
||||
}
|
||||
let style = PrimitiveStyleBuilder::new()
|
||||
.fill_color(primary)
|
||||
.build();
|
||||
|
||||
let _ = Rectangle::new(rect_point, Size::new(45, 25)).into_styled(style).draw(display);
|
||||
} else {
|
||||
yes_color = primary;
|
||||
no_color = primary;
|
||||
}
|
||||
|
||||
_ = MED_FONT.render_aligned(
|
||||
"Yes",
|
||||
Point{x: 110, y: 130},
|
||||
u8g2_fonts::types::VerticalPosition::Top,
|
||||
u8g2_fonts::types::HorizontalAlignment::Right,
|
||||
u8g2_fonts::types::FontColor::Transparent(yes_color),
|
||||
display,
|
||||
);
|
||||
|
||||
_ = MED_FONT.render_aligned(
|
||||
"No",
|
||||
Point{x: 135, y: 130},
|
||||
u8g2_fonts::types::VerticalPosition::Top,
|
||||
u8g2_fonts::types::HorizontalAlignment::Left,
|
||||
u8g2_fonts::types::FontColor::Transparent(no_color),
|
||||
display,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn setting_scroll<A>(ctx: &SystemState, selection: &SettingScreenItem, target: &mut A) -> ()
|
||||
where A: DrawTarget<Color = Rgb565>
|
||||
{
|
||||
let primary = ctx.settings.color_scheme.get_color(&crate::display::ColorType::Primary);
|
||||
let background = ctx.settings.color_scheme.get_color(&crate::display::ColorType::Background);
|
||||
|
||||
if !selection.inner {
|
||||
let above = selection.entry.prev().as_str();
|
||||
let selected = selection.entry.as_str();
|
||||
let below = selection.entry.next().as_str();
|
||||
|
||||
let _above = MED_FONT.render_aligned(
|
||||
above,
|
||||
Point::new(120, 50),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
|
||||
let _selected = MED_PLUS_FONT.render_aligned(
|
||||
selected,
|
||||
Point::new(120, 120),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
|
||||
let _below = MED_FONT.render_aligned(
|
||||
below,
|
||||
Point::new(120, 190),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
} else {
|
||||
setting_item(target);
|
||||
match selection.entry {
|
||||
SettingScreenEntry::NewGame => {
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
selection.entry.as_str(),
|
||||
Point::new(120, 120),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(primary),
|
||||
target,
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::Opponents => {
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
ctx.settings.opponenets.to_string().as_str(),
|
||||
ctx.positions.center,
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::StartingLife => {
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
ctx.settings.starting_life.to_string().as_str(),
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::Colors => {
|
||||
let current_scheme_number: u8 = ctx.settings.color_scheme.into();
|
||||
let prev_scheme_number;
|
||||
let check_sub = current_scheme_number.checked_sub(1);
|
||||
if let Some(p) = check_sub {
|
||||
prev_scheme_number = p;
|
||||
} else {
|
||||
prev_scheme_number = COLORSCHEMES as u8 - 1;
|
||||
}
|
||||
let prev_scheme: ColorScheme = prev_scheme_number.into();
|
||||
|
||||
let next_scheme_number;
|
||||
let check_add = current_scheme_number + 1;
|
||||
if check_add >= COLORSCHEMES as u8 {
|
||||
next_scheme_number = 0;
|
||||
} else {
|
||||
next_scheme_number = check_add;
|
||||
}
|
||||
let next_scheme: ColorScheme = next_scheme_number.into();
|
||||
|
||||
let _ = MED_FONT.render_aligned(
|
||||
prev_scheme.as_str(),
|
||||
Point::new(120, 70),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
ctx.settings.color_scheme.as_str(),
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
|
||||
let _ = MED_FONT.render_aligned(
|
||||
next_scheme.as_str(),
|
||||
Point::new(120, 170),
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
},
|
||||
SettingScreenEntry::Brightness => {
|
||||
let _ = MED_PLUS_FONT.render_aligned(
|
||||
ctx.settings.brightness.as_str(),
|
||||
ctx.positions.center,
|
||||
u8g2_fonts::types::VerticalPosition::Center,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
}
|
||||
SettingScreenEntry::ShowTax => {
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nCommand Tax?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_cmd_tax));
|
||||
},
|
||||
SettingScreenEntry::ShowEnergy => {
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nEnergy?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_energy));
|
||||
},
|
||||
SettingScreenEntry::ShowExperience => {
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nExperience?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_experience));
|
||||
},
|
||||
SettingScreenEntry::ShowTickets => {
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nTickets?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_tickets));
|
||||
},
|
||||
SettingScreenEntry::ShowPoison => {
|
||||
let _ = MED_FONT.render_aligned(
|
||||
"Show\nPoison?",
|
||||
Point::new(120, 120),
|
||||
u8g2_fonts::types::VerticalPosition::Bottom,
|
||||
u8g2_fonts::types::HorizontalAlignment::Center,
|
||||
u8g2_fonts::types::FontColor::Transparent(primary),
|
||||
target
|
||||
);
|
||||
draw_yes_no(primary, background, target, Some(ctx.settings.show_infect));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setting_item<A>(target: &mut A) -> ()
|
||||
where A: DrawTarget<Color = Rgb565>
|
||||
{
|
||||
let _okay_outline_1 = CHECK.render_aligned(
|
||||
'\u{0040}',
|
||||
Point::new(26, 121),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(Rgb565::BLACK),
|
||||
target
|
||||
);
|
||||
let _okay_outline_2 = CHECK.render_aligned(
|
||||
'\u{0040}',
|
||||
Point::new(26, 119),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(Rgb565::BLACK),
|
||||
target
|
||||
);
|
||||
let _okay_outline_3 = CHECK.render_aligned(
|
||||
'\u{0040}',
|
||||
Point::new(24, 121),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(Rgb565::BLACK),
|
||||
target
|
||||
);
|
||||
let _okay_outline_4 = CHECK.render_aligned(
|
||||
'\u{0040}',
|
||||
Point::new(24, 119),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(Rgb565::BLACK),
|
||||
target
|
||||
);
|
||||
|
||||
let _okay = CHECK.render_aligned(
|
||||
'\u{0040}',
|
||||
Point::new(25, 120),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(Rgb565::new(1, 54, 10)),
|
||||
target
|
||||
);
|
||||
|
||||
let _cancel = CHECK.render_aligned(
|
||||
'\u{0044}',
|
||||
Point::new(215, 120),
|
||||
VerticalPosition::Center,
|
||||
HorizontalAlignment::Center,
|
||||
FontColor::Transparent(Rgb565::new(25, 8, 5)),
|
||||
target
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
setting scroller -> internal screen check ok/ x cancel
|
||||
*/
|
||||
387
src/state.rs
Normal file
387
src/state.rs
Normal file
@@ -0,0 +1,387 @@
|
||||
use core::panic;
|
||||
|
||||
use crate::display::ColorScheme;
|
||||
use embedded_graphics::prelude::{Angle, Point};
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::{string::String, string::ToString};
|
||||
|
||||
pub struct SystemState {
|
||||
pub settings: Settings,
|
||||
pub game: Game,
|
||||
pub positions: Positions,
|
||||
pub screen: Screen,
|
||||
}
|
||||
|
||||
impl SystemState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
settings: Settings {
|
||||
opponenets: 1,
|
||||
starting_life: 40,
|
||||
brightness: Brightness::Three,
|
||||
color_scheme: ColorScheme::Dark,
|
||||
show_cmd_tax: true,
|
||||
show_infect: true,
|
||||
show_energy: true,
|
||||
show_experience: true,
|
||||
show_tickets: true,
|
||||
},
|
||||
game: Game { life: 40, cmd_dmg: [CommanderDamage{main: 0, partner: 0, is_partner: true};6], infect: 0, cmd_tax: CommanderDamage { main: 0, partner: 0, is_partner: false }, energy: 0, experience: 0, tickets: 0, monarch: false},
|
||||
positions: Positions::init(),
|
||||
screen: Screen::Main(MainScreenItem::Life),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Settings {
|
||||
pub opponenets: u8,
|
||||
pub starting_life: i32,
|
||||
pub color_scheme: ColorScheme,
|
||||
pub brightness: Brightness,
|
||||
pub show_cmd_tax: bool,
|
||||
pub show_infect: bool,
|
||||
pub show_experience: bool,
|
||||
pub show_energy: bool,
|
||||
pub show_tickets: bool,
|
||||
}
|
||||
|
||||
pub struct Game {
|
||||
pub life: i32,
|
||||
pub cmd_dmg: [CommanderDamage;6],
|
||||
pub cmd_tax: CommanderDamage,
|
||||
pub infect: u8,
|
||||
pub energy: u16,
|
||||
pub experience: u16,
|
||||
pub tickets: u16,
|
||||
pub monarch: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct CommanderDamage {
|
||||
pub main: u8,
|
||||
pub partner: u8,
|
||||
pub is_partner: bool,
|
||||
}
|
||||
|
||||
impl CommanderDamage {
|
||||
pub fn as_string_horizontal(&self) -> String {
|
||||
match self.is_partner {
|
||||
true => {
|
||||
let mut tmpa = self.main.to_string();
|
||||
let tmpb = self.partner.to_string();
|
||||
tmpa.push('|');
|
||||
tmpa.push_str(&tmpb);
|
||||
tmpa
|
||||
},
|
||||
false => {
|
||||
self.main.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn as_string_vetical(&self) -> String {
|
||||
match self.is_partner {
|
||||
true => {
|
||||
let mut tmpa = self.main.to_string();
|
||||
let tmpb = self.partner.to_string();
|
||||
tmpa.push('\n');
|
||||
tmpa.push_str(&tmpb);
|
||||
tmpa
|
||||
},
|
||||
false => {
|
||||
self.main.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Positions {
|
||||
top_even: [PeripheralLocation;6],
|
||||
top_odd: [PeripheralLocation;5],
|
||||
bottom_even: [PeripheralLocation;6],
|
||||
bottom_odd: [PeripheralLocation;5],
|
||||
pub top_setting_locations: [PeripheralLocation;5],
|
||||
pub bottom_setting_locations: [PeripheralLocation;5],
|
||||
pub center: Point,
|
||||
}
|
||||
|
||||
impl Positions {
|
||||
pub fn init() -> Self {
|
||||
let top_odd = [
|
||||
PeripheralLocation{ position: Point::new(38, 71), angle: Angle::from_degrees(150.)},
|
||||
PeripheralLocation{ position: Point::new(72, 37), angle: Angle::from_degrees(120.)},
|
||||
PeripheralLocation{ position: Point::new(120, 20), angle: Angle::from_degrees(90.)},
|
||||
PeripheralLocation{ position: Point::new(168, 37), angle: Angle::from_degrees(60.)},
|
||||
PeripheralLocation{ position: Point::new(202, 71), angle: Angle::from_degrees(30.)},
|
||||
];
|
||||
let top_even = [
|
||||
PeripheralLocation{ position: Point::new(23, 96), angle: Angle::from_degrees(165.)},
|
||||
PeripheralLocation{ position: Point::new(53, 52), angle: Angle::from_degrees(135.)},
|
||||
PeripheralLocation{ position: Point::new(95, 27), angle: Angle::from_degrees(105.)},
|
||||
PeripheralLocation{ position: Point::new(145, 27), angle: Angle::from_degrees(75.)},
|
||||
PeripheralLocation{ position: Point::new(187, 52), angle: Angle::from_degrees(45.)},
|
||||
PeripheralLocation{ position: Point::new(212, 96), angle: Angle::from_degrees(15.)},
|
||||
];
|
||||
let bottom_odd = [
|
||||
PeripheralLocation{ position: Point::new(32, 170), angle: Angle::from_degrees(210.)},
|
||||
PeripheralLocation{ position: Point::new(70, 208), angle: Angle::from_degrees(240.)},
|
||||
PeripheralLocation{ position: Point::new(120, 215), angle: Angle::from_degrees(270.)},
|
||||
PeripheralLocation{ position: Point::new(168, 203), angle: Angle::from_degrees(300.)},
|
||||
PeripheralLocation{ position: Point::new(202, 169), angle: Angle::from_degrees(330.)},
|
||||
];
|
||||
let bottom_even = [
|
||||
PeripheralLocation{ position: Point::new(28, 146), angle: Angle::from_degrees(195.)},
|
||||
PeripheralLocation{ position: Point::new(48, 190), angle: Angle::from_degrees(225.)},
|
||||
PeripheralLocation{ position: Point::new(95, 213), angle: Angle::from_degrees(255.)},
|
||||
PeripheralLocation{ position: Point::new(145, 213), angle: Angle::from_degrees(285.)},
|
||||
PeripheralLocation{ position: Point::new(187, 188), angle: Angle::from_degrees(315.)},
|
||||
PeripheralLocation{ position: Point::new(212, 146), angle: Angle::from_degrees(345.)},
|
||||
];
|
||||
let top_setting_locations = [
|
||||
PeripheralLocation{ position: Point::new(38, 91), angle: Angle::from_degrees(162.)},
|
||||
PeripheralLocation{ position: Point::new(64, 53), angle: Angle::from_degrees(126.)},
|
||||
PeripheralLocation{ position: Point::new(120, 25), angle: Angle::from_degrees(90.)},
|
||||
PeripheralLocation{ position: Point::new(176, 53), angle: Angle::from_degrees(54.)},
|
||||
PeripheralLocation{ position: Point::new(210, 91), angle: Angle::from_degrees(18.)},
|
||||
];
|
||||
let bottom_setting_locations = [
|
||||
PeripheralLocation{ position: Point::new(33, 170), angle: Angle::from_degrees(210.)},//(43,169)
|
||||
PeripheralLocation{ position: Point::new(72, 203), angle: Angle::from_degrees(240.)},
|
||||
PeripheralLocation{ position: Point::new(120, 215), angle: Angle::from_degrees(270.)},
|
||||
PeripheralLocation{ position: Point::new(168, 203), angle: Angle::from_degrees(300.)},
|
||||
PeripheralLocation{ position: Point::new(202, 169), angle: Angle::from_degrees(330.)},
|
||||
];
|
||||
|
||||
Self {
|
||||
top_even,
|
||||
top_odd,
|
||||
bottom_even,
|
||||
bottom_odd,
|
||||
top_setting_locations,
|
||||
bottom_setting_locations,
|
||||
center: Point { x: 120, y: 120 }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_top_list(&self, count: u8) -> &[PeripheralLocation] {
|
||||
match count {
|
||||
1 => &self.top_odd[2..3],
|
||||
2 => &self.top_even[2..4],
|
||||
3 => &self.top_odd[1..4],
|
||||
4 => &self.top_even[1..5],
|
||||
5 => &self.top_odd,
|
||||
6 => &self.top_even,
|
||||
_ => panic!("Invalid count")
|
||||
}
|
||||
}
|
||||
pub fn get_bottom_list(&self, count: u8) -> &[PeripheralLocation] {
|
||||
match count {
|
||||
1 => &self.bottom_odd[2..3],
|
||||
2 => &self.bottom_even[2..4],
|
||||
3 => &self.bottom_odd[1..4],
|
||||
4 => &self.bottom_even[1..5],
|
||||
5 => &self.bottom_odd,
|
||||
6 => &self.bottom_even,
|
||||
_ => panic!("Invalid count")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Screen{
|
||||
Main(MainScreenItem),
|
||||
Settings(SettingScreenItem),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy)]
|
||||
pub enum MainScreenItem {
|
||||
Life,
|
||||
Dmg1,
|
||||
Dmg2,
|
||||
Dmg3,
|
||||
Dmg4,
|
||||
Dmg5,
|
||||
Dmg6,
|
||||
Tax,
|
||||
Energy,
|
||||
Experience,
|
||||
Tickets,
|
||||
Poison,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub struct SettingScreenItem {
|
||||
pub entry: SettingScreenEntry,
|
||||
pub inner: bool,
|
||||
pub prev: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum SettingScreenEntry {
|
||||
NewGame,
|
||||
Opponents,
|
||||
StartingLife,
|
||||
Colors,
|
||||
Brightness,
|
||||
ShowTax,
|
||||
ShowEnergy,
|
||||
ShowExperience,
|
||||
ShowTickets,
|
||||
ShowPoison,
|
||||
}
|
||||
|
||||
impl SettingScreenEntry {
|
||||
pub fn prev(&self) -> Self {
|
||||
match self {
|
||||
SettingScreenEntry::NewGame => Self::ShowPoison,
|
||||
SettingScreenEntry::Opponents => Self::NewGame,
|
||||
SettingScreenEntry::StartingLife => Self::Opponents,
|
||||
SettingScreenEntry::Colors => Self::StartingLife,
|
||||
SettingScreenEntry::Brightness => Self::Colors,
|
||||
SettingScreenEntry::ShowTax => Self::Brightness,
|
||||
SettingScreenEntry::ShowEnergy => Self::ShowTax,
|
||||
SettingScreenEntry::ShowExperience => Self::ShowEnergy,
|
||||
SettingScreenEntry::ShowTickets => Self::ShowExperience,
|
||||
SettingScreenEntry::ShowPoison => Self::ShowTickets,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(&self) -> Self {
|
||||
match self {
|
||||
SettingScreenEntry::NewGame => Self::Opponents,
|
||||
SettingScreenEntry::Opponents => Self::StartingLife,
|
||||
SettingScreenEntry::StartingLife => Self::Colors,
|
||||
SettingScreenEntry::Colors => Self::Brightness,
|
||||
SettingScreenEntry::Brightness => Self::ShowTax,
|
||||
SettingScreenEntry::ShowTax => Self::ShowEnergy,
|
||||
SettingScreenEntry::ShowEnergy => Self::ShowExperience,
|
||||
SettingScreenEntry::ShowExperience => Self::ShowTickets,
|
||||
SettingScreenEntry::ShowTickets => Self::ShowPoison,
|
||||
SettingScreenEntry::ShowPoison => Self::NewGame,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
SettingScreenEntry::NewGame => "New Game",
|
||||
SettingScreenEntry::Opponents => "Opponents",
|
||||
SettingScreenEntry::StartingLife => "Starting\nLife",
|
||||
SettingScreenEntry::Colors => "Color\nScheme",
|
||||
SettingScreenEntry::Brightness => "Brightness",
|
||||
SettingScreenEntry::ShowTax => "Show\nCommander\nTax",
|
||||
SettingScreenEntry::ShowEnergy => "Show\nEnergy",
|
||||
SettingScreenEntry::ShowExperience => "Show\nExperience",
|
||||
SettingScreenEntry::ShowTickets => "Show\nTickets",
|
||||
SettingScreenEntry::ShowPoison => "Show\nPoison",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Brightness {
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five,
|
||||
Six,
|
||||
Seven,
|
||||
Eight,
|
||||
Nine,
|
||||
Ten,
|
||||
}
|
||||
|
||||
impl Brightness {
|
||||
pub fn inc(self) -> Self {
|
||||
match self {
|
||||
Brightness::One => Self::Two,
|
||||
Brightness::Two => Self::Three,
|
||||
Brightness::Three => Self::Four,
|
||||
Brightness::Four => Self::Five,
|
||||
Brightness::Five => Self::Six,
|
||||
Brightness::Six => Self::Seven,
|
||||
Brightness::Seven => Self::Eight,
|
||||
Brightness::Eight => Self::Nine,
|
||||
Brightness::Nine => Self::Ten,
|
||||
Brightness::Ten => Self::Ten,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dec(self) -> Self {
|
||||
match self {
|
||||
Brightness::One => Self::One,
|
||||
Brightness::Two => Self::One,
|
||||
Brightness::Three => Self::Two,
|
||||
Brightness::Four => Self::Three,
|
||||
Brightness::Five => Self::Four,
|
||||
Brightness::Six => Self::Five,
|
||||
Brightness::Seven => Self::Six,
|
||||
Brightness::Eight => Self::Seven,
|
||||
Brightness::Nine => Self::Eight,
|
||||
Brightness::Ten => Self::Nine,
|
||||
}
|
||||
}
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Brightness::One => "Min",
|
||||
Brightness::Two => "2",
|
||||
Brightness::Three => "3",
|
||||
Brightness::Four => "4",
|
||||
Brightness::Five => "5",
|
||||
Brightness::Six => "6",
|
||||
Brightness::Seven => "7",
|
||||
Brightness::Eight => "8",
|
||||
Brightness::Nine => "9",
|
||||
Brightness::Ten => "Max",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u32> for Brightness {
|
||||
fn into(self) -> u32 {
|
||||
match self {
|
||||
Brightness::One => 15,
|
||||
Brightness::Two => 20,
|
||||
Brightness::Three => 30,
|
||||
Brightness::Four => 40,
|
||||
Brightness::Five => 50,
|
||||
Brightness::Six => 60,
|
||||
Brightness::Seven => 70,
|
||||
Brightness::Eight => 80,
|
||||
Brightness::Nine => 90,
|
||||
Brightness::Ten => 100,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Brightness {
|
||||
fn from(value: u32) -> Self {
|
||||
if value <= 15 {
|
||||
Brightness::One
|
||||
} else if value <= 20 {
|
||||
Brightness::Two
|
||||
} else if value <= 30 {
|
||||
Brightness::Three
|
||||
} else if value <= 40 {
|
||||
Brightness::Four
|
||||
} else if value <= 50 {
|
||||
Brightness::Five
|
||||
} else if value <= 60 {
|
||||
Brightness::Six
|
||||
} else if value <= 70 {
|
||||
Brightness::Seven
|
||||
} else if value <= 80 {
|
||||
Brightness::Eight
|
||||
} else if value <= 90 {
|
||||
Brightness::Nine
|
||||
} else {
|
||||
Brightness::Ten
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PeripheralLocation {
|
||||
pub position: Point,
|
||||
pub angle: Angle,
|
||||
}
|
||||
406
src/touch.rs
Normal file
406
src/touch.rs
Normal file
@@ -0,0 +1,406 @@
|
||||
use crate::{display::ColorScheme, state::{CommanderDamage, Game, MainScreenItem, Screen, SettingScreenEntry, SettingScreenItem, SystemState}};
|
||||
|
||||
const CMDDMGLIST: [MainScreenItem;6] = [
|
||||
MainScreenItem::Dmg1,
|
||||
MainScreenItem::Dmg2,
|
||||
MainScreenItem::Dmg3,
|
||||
MainScreenItem::Dmg4,
|
||||
MainScreenItem::Dmg5,
|
||||
MainScreenItem::Dmg6,
|
||||
];
|
||||
|
||||
pub fn get_touch_action(x: f32, y: f32, gesture: u8, ctx: &mut SystemState) -> () {
|
||||
let x = x - 120.;
|
||||
let y = -(y - 120.);
|
||||
let touch_rad = (x*x)+(y*y);
|
||||
let angle;
|
||||
|
||||
let next_state;
|
||||
|
||||
if (gesture == 0x3) | (gesture == 0x4) {
|
||||
ctx.screen = match &ctx.screen {
|
||||
Screen::Main(_) => Screen::Settings(SettingScreenItem { entry: SettingScreenEntry::NewGame, inner: false , prev: None}),
|
||||
Screen::Settings(_) => Screen::Main(MainScreenItem::Life),
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
match &ctx.screen {
|
||||
Screen::Main(selected) => {
|
||||
|
||||
let mut bottom_selectable_list: [Option<MainScreenItem>;5] = [const {None};5];
|
||||
let mut pos = 0;
|
||||
if ctx.settings.show_cmd_tax {
|
||||
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Tax);
|
||||
pos += 1;
|
||||
}
|
||||
if ctx.settings.show_energy {
|
||||
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Energy);
|
||||
pos+=1;
|
||||
};
|
||||
if ctx.settings.show_experience {
|
||||
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Experience);
|
||||
pos+=1;
|
||||
};
|
||||
if ctx.settings.show_tickets {
|
||||
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Tickets);
|
||||
pos+=1;
|
||||
};
|
||||
if ctx.settings.show_infect {
|
||||
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Poison);
|
||||
};
|
||||
|
||||
let bottom_count = bottom_selectable_list.iter().fold(0, |acc, x| acc+x.is_some() as u8);
|
||||
|
||||
if touch_rad > (70.*70.) {
|
||||
angle = atan2_norm(y, x)*90.;
|
||||
//ctx.game.life = angle as i32; //debug
|
||||
let top;
|
||||
let check_angles = if y >= 0. {
|
||||
if ctx.settings.opponenets == 0 {
|
||||
return;
|
||||
}
|
||||
top = true;
|
||||
ctx.positions.get_top_list(ctx.settings.opponenets)
|
||||
} else {
|
||||
if bottom_count == 0 {
|
||||
return;
|
||||
}
|
||||
top = false;
|
||||
ctx.positions.get_bottom_list(bottom_count)
|
||||
};
|
||||
|
||||
let touch_item = match check_angles.iter().position(|x| (x.angle.to_degrees()-angle).abs()<15.) {
|
||||
Some(loc) => loc,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let sel_match = if top {
|
||||
Some(CMDDMGLIST.into_iter().nth(touch_item).unwrap_or(MainScreenItem::Dmg1))
|
||||
} else {
|
||||
bottom_selectable_list[touch_item]
|
||||
};
|
||||
|
||||
if let Some(selected_item) = sel_match {
|
||||
if selected_item == *selected {
|
||||
next_state = Screen::Main(MainScreenItem::Life);
|
||||
} else {
|
||||
next_state = Screen::Main(selected_item);
|
||||
}
|
||||
} else {
|
||||
next_state = Screen::Main(MainScreenItem::Life);
|
||||
}
|
||||
|
||||
} else {
|
||||
match selected {
|
||||
crate::state::MainScreenItem::Life => {
|
||||
let d = touch_inc_dec(y, gesture);
|
||||
ctx.game.life = ctx.game.life.saturating_add(d as i32);
|
||||
},
|
||||
|
||||
crate::state::MainScreenItem::Dmg1 => {
|
||||
cmd_dmg_w_swap(ctx, x, y, gesture, 0);
|
||||
},
|
||||
crate::state::MainScreenItem::Dmg2 => {
|
||||
cmd_dmg_w_swap(ctx, x, y, gesture, 1);
|
||||
},
|
||||
crate::state::MainScreenItem::Dmg3 => {
|
||||
cmd_dmg_w_swap(ctx, x, y, gesture, 2);
|
||||
},
|
||||
crate::state::MainScreenItem::Dmg4 => {
|
||||
cmd_dmg_w_swap(ctx, x, y, gesture, 3);
|
||||
},
|
||||
crate::state::MainScreenItem::Dmg5 => {
|
||||
cmd_dmg_w_swap(ctx, x, y, gesture, 4);
|
||||
},
|
||||
crate::state::MainScreenItem::Dmg6 => {
|
||||
cmd_dmg_w_swap(ctx, x, y, gesture, 5);
|
||||
},
|
||||
|
||||
crate::state::MainScreenItem::Tax => {
|
||||
cmd_tax_w_swap(ctx, x, y, gesture);
|
||||
},
|
||||
crate::state::MainScreenItem::Energy => {
|
||||
let d = touch_inc_dec(y, gesture);
|
||||
ctx.game.energy = ctx.game.energy.saturating_add_signed(d.into());
|
||||
},
|
||||
crate::state::MainScreenItem::Experience => {
|
||||
let d = touch_inc_dec(y, gesture);
|
||||
ctx.game.experience = ctx.game.experience.saturating_add_signed(d.into());
|
||||
},
|
||||
crate::state::MainScreenItem::Tickets => {
|
||||
let d = touch_inc_dec(y, gesture);
|
||||
ctx.game.tickets = ctx.game.tickets.saturating_add_signed(d.into());
|
||||
},
|
||||
crate::state::MainScreenItem::Poison => {
|
||||
let d = touch_inc_dec(y, gesture);
|
||||
ctx.game.infect = ctx.game.infect.saturating_add_signed(d.into());
|
||||
},
|
||||
};
|
||||
next_state = ctx.screen;
|
||||
};
|
||||
},
|
||||
Screen::Settings(selected) => {
|
||||
if !selected.inner {
|
||||
if gesture == 0x01_u8 {
|
||||
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry.prev(), inner: false, prev: selected.prev });
|
||||
} else if gesture == 0x02_u8 {
|
||||
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry.next(), inner: false, prev: selected.prev });
|
||||
} else {
|
||||
if y > 55. {
|
||||
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry.prev(), inner: false, prev: selected.prev});
|
||||
} else if y < -55. {
|
||||
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry.next(), inner: false, prev: selected.prev });
|
||||
} else {
|
||||
let prev = match selected.entry {
|
||||
SettingScreenEntry::NewGame => None,
|
||||
SettingScreenEntry::Opponents => Some(ctx.settings.opponenets as u32),
|
||||
SettingScreenEntry::StartingLife => Some(ctx.settings.starting_life as u32),
|
||||
SettingScreenEntry::Colors => Some(Into::<u8>::into(ctx.settings.color_scheme) as u32),
|
||||
SettingScreenEntry::Brightness => Some(ctx.settings.brightness.into()),
|
||||
SettingScreenEntry::ShowTax => Some(ctx.settings.show_cmd_tax as u32),
|
||||
SettingScreenEntry::ShowEnergy => Some(ctx.settings.show_energy as u32),
|
||||
SettingScreenEntry::ShowExperience => Some(ctx.settings.show_experience as u32),
|
||||
SettingScreenEntry::ShowTickets => Some(ctx.settings.show_tickets as u32),
|
||||
SettingScreenEntry::ShowPoison => Some(ctx.settings.show_infect as u32),
|
||||
};
|
||||
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry, inner: true, prev: prev});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if x < -75. {
|
||||
match selected.entry {
|
||||
SettingScreenEntry::NewGame => {
|
||||
ctx.game = Game {
|
||||
life: ctx.settings.starting_life,
|
||||
cmd_dmg: [CommanderDamage{main: 0, partner: 0, is_partner: false};6],
|
||||
cmd_tax: CommanderDamage { main: 0, partner: 0, is_partner: false },
|
||||
infect: 0,
|
||||
energy: 0,
|
||||
experience: 0,
|
||||
tickets: 0,
|
||||
monarch: false,
|
||||
};
|
||||
next_state = Screen::Main(MainScreenItem::Life);
|
||||
},
|
||||
_ => {
|
||||
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry, inner: false, prev: None })
|
||||
}
|
||||
}
|
||||
} else if x > 75. {
|
||||
match selected.entry {
|
||||
SettingScreenEntry::NewGame => {},
|
||||
SettingScreenEntry::Opponents => {
|
||||
ctx.settings.opponenets = selected.prev.unwrap_or(0) as u8;
|
||||
},
|
||||
SettingScreenEntry::StartingLife => {
|
||||
ctx.settings.starting_life = selected.prev.unwrap_or(0) as i32;
|
||||
},
|
||||
SettingScreenEntry::Colors => {
|
||||
ctx.settings.color_scheme =Into::<ColorScheme>::into(selected.prev.unwrap_or(0) as u8);
|
||||
},
|
||||
SettingScreenEntry::Brightness => {
|
||||
ctx.settings.brightness = selected.prev.unwrap_or(0).into();
|
||||
},
|
||||
SettingScreenEntry::ShowTax => {
|
||||
ctx.settings.show_cmd_tax = selected.prev.unwrap_or_default() != 0;
|
||||
},
|
||||
SettingScreenEntry::ShowEnergy => {
|
||||
ctx.settings.show_energy = selected.prev.unwrap_or_default() != 0;
|
||||
},
|
||||
SettingScreenEntry::ShowExperience => {
|
||||
ctx.settings.show_experience = selected.prev.unwrap_or_default() != 0;
|
||||
},
|
||||
SettingScreenEntry::ShowTickets => {
|
||||
ctx.settings.show_tickets = selected.prev.unwrap_or_default() != 0;
|
||||
},
|
||||
SettingScreenEntry::ShowPoison => {
|
||||
ctx.settings.show_infect = selected.prev.unwrap_or_default() != 0;
|
||||
},
|
||||
}
|
||||
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry, inner: false, prev: None })
|
||||
} else {
|
||||
match selected.entry {
|
||||
SettingScreenEntry::NewGame => {
|
||||
|
||||
},
|
||||
SettingScreenEntry::Opponents => {
|
||||
ctx.settings.opponenets = ctx.settings.opponenets.saturating_add_signed(touch_inc_dec(y, gesture));
|
||||
},
|
||||
SettingScreenEntry::StartingLife => {
|
||||
ctx.settings.starting_life = ctx.settings.starting_life.saturating_add(touch_inc_dec(y, gesture) as i32);
|
||||
},
|
||||
SettingScreenEntry::Colors => {
|
||||
if y > 40. {
|
||||
ctx.settings.color_scheme = ctx.settings.color_scheme.dec();
|
||||
} else if y < -40. {
|
||||
ctx.settings.color_scheme = ctx.settings.color_scheme.inc();
|
||||
}
|
||||
},
|
||||
SettingScreenEntry::Brightness => {
|
||||
let tmp = touch_inc_dec(y, gesture);
|
||||
if tmp > 0 {
|
||||
ctx.settings.brightness = ctx.settings.brightness.inc();
|
||||
} else {
|
||||
ctx.settings.brightness = ctx.settings.brightness.dec();
|
||||
}
|
||||
},
|
||||
SettingScreenEntry::ShowTax => {
|
||||
let det = select_button(x, y, gesture);
|
||||
if let Some(i) = det {
|
||||
ctx.settings.show_cmd_tax = i;
|
||||
}
|
||||
},
|
||||
SettingScreenEntry::ShowEnergy => {
|
||||
let det = select_button(x, y, gesture);
|
||||
if let Some(i) = det {
|
||||
ctx.settings.show_energy = i;
|
||||
}
|
||||
},
|
||||
SettingScreenEntry::ShowExperience => {
|
||||
let det = select_button(x, y, gesture);
|
||||
if let Some(i) = det {
|
||||
ctx.settings.show_experience = i;
|
||||
}
|
||||
},
|
||||
SettingScreenEntry::ShowTickets => {
|
||||
let det = select_button(x, y, gesture);
|
||||
if let Some(i) = det {
|
||||
ctx.settings.show_tickets = i;
|
||||
}
|
||||
},
|
||||
SettingScreenEntry::ShowPoison => {
|
||||
let det = select_button(x, y, gesture);
|
||||
if let Some(i) = det {
|
||||
ctx.settings.show_infect = i;
|
||||
}
|
||||
},
|
||||
}
|
||||
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry, inner: selected.inner, prev: selected.prev })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.screen = next_state;
|
||||
}
|
||||
|
||||
/// Approximates `atan2(y,x)` normalized to the `[0, 4)` range with a maximum
|
||||
/// error of `0.1620` degrees.
|
||||
fn atan2_norm(lhs: f32, rhs: f32) -> f32 {
|
||||
const SIGN_MASK: u32 = 0x8000_0000;
|
||||
const B: f32 = 0.596_227;
|
||||
|
||||
let y = lhs;
|
||||
let x = rhs;
|
||||
|
||||
// Extract sign bits from floating point values
|
||||
let ux_s = SIGN_MASK & x.to_bits();
|
||||
let uy_s = SIGN_MASK & y.to_bits();
|
||||
|
||||
// Determine quadrant offset
|
||||
let q = ((!ux_s & uy_s) >> 29 | ux_s >> 30) as f32;
|
||||
|
||||
// Calculate arctangent in the first quadrant
|
||||
let bxy_a = (B * x * y).abs();
|
||||
let n = bxy_a + y * y;
|
||||
let atan_1q = n / (x * x + bxy_a + n);
|
||||
|
||||
// Translate it to the proper quadrant
|
||||
let uatan_2q = (ux_s ^ uy_s) | atan_1q.to_bits();
|
||||
q + f32::from_bits(uatan_2q)
|
||||
}
|
||||
|
||||
fn touch_inc_dec(y: f32, gesture: u8) -> i8 {
|
||||
if gesture == 0x05 {
|
||||
if y >= 0. {
|
||||
1
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
} else if gesture == 0x02 {
|
||||
5
|
||||
} else if gesture == 0x01 {
|
||||
-5
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn touch_left_right(x: f32, y: f32, gesture: u8) -> (i8, bool) {
|
||||
if x <= 0. {
|
||||
(touch_inc_dec(y, gesture), true)
|
||||
} else {
|
||||
(touch_inc_dec(y, gesture), false)
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_dmg_calc(ctx: &mut SystemState, x: f32, y: f32, gesture: u8, pos: usize) {
|
||||
if ctx.game.cmd_dmg[pos].is_partner {
|
||||
let (d, left) = touch_left_right(x, y, gesture);
|
||||
if left {
|
||||
ctx.game.cmd_dmg[pos].main = ctx.game.cmd_dmg[pos].main.saturating_add_signed(d);
|
||||
} else {
|
||||
ctx.game.cmd_dmg[pos].partner = ctx.game.cmd_dmg[pos].partner.saturating_add_signed(d);
|
||||
}
|
||||
} else {
|
||||
let d = touch_inc_dec(y, gesture);
|
||||
ctx.game.cmd_dmg[pos].main = ctx.game.cmd_dmg[pos].main.saturating_add_signed(d);
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_tax_calc(ctx: &mut SystemState, x: f32, y: f32, gesture: u8) {
|
||||
if ctx.game.cmd_tax.is_partner {
|
||||
let (mut d, left) = touch_left_right(x, y, gesture);
|
||||
|
||||
if d >= 0 {
|
||||
d = 2;
|
||||
} else {
|
||||
d =-2;
|
||||
}
|
||||
|
||||
if left {
|
||||
ctx.game.cmd_tax.main = ctx.game.cmd_tax.main.saturating_add_signed(d);
|
||||
} else {
|
||||
ctx.game.cmd_tax.partner = ctx.game.cmd_tax.partner.saturating_add_signed(d);
|
||||
}
|
||||
} else {
|
||||
let mut d = touch_inc_dec(y, gesture);
|
||||
|
||||
if d >= 0 {
|
||||
d = 2;
|
||||
} else {
|
||||
d =-2;
|
||||
}
|
||||
|
||||
ctx.game.cmd_tax.main = ctx.game.cmd_tax.main.saturating_add_signed(d);
|
||||
}
|
||||
}
|
||||
|
||||
/// true is left selection false is right selection
|
||||
fn select_button(x: f32, y: f32, _gesture: u8) -> Option<bool> {
|
||||
if (y<60.) & (y>-60.) {
|
||||
if x<=0. {
|
||||
Some(true)
|
||||
} else {
|
||||
Some(false)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_dmg_w_swap(ctx: &mut SystemState, x: f32, y: f32, gesture: u8, pos: usize) {
|
||||
if (x>-20.) & (x<20.) & (y< -30.)&(y>-50.) {
|
||||
ctx.game.cmd_dmg[pos].is_partner = !ctx.game.cmd_dmg[pos].is_partner;
|
||||
} else {
|
||||
cmd_dmg_calc(ctx, x, y, gesture, pos);
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_tax_w_swap(ctx: &mut SystemState, x: f32, y: f32, gesture: u8) {
|
||||
if (x>-20.) & (x<20.) & (y< -30.)&(y>-50.) {
|
||||
ctx.game.cmd_tax.is_partner = !ctx.game.cmd_tax.is_partner;
|
||||
} else {
|
||||
cmd_tax_calc(ctx, x, y, gesture);
|
||||
}
|
||||
}
|
||||
149
template.yaml
Normal file
149
template.yaml
Normal file
@@ -0,0 +1,149 @@
|
||||
options:
|
||||
- !Option
|
||||
name: unstable-hal
|
||||
display_name: Enable unstable HAL features.
|
||||
help: "This configuration enables unstable esp-hal features.
|
||||
These come with no stability guarantees, and could be changed or removed at any time."
|
||||
|
||||
- !Option
|
||||
name: alloc
|
||||
display_name: Enable allocations via the esp-alloc crate.
|
||||
help: esp-alloc comes with no stability guarantees at this time.
|
||||
|
||||
- !Option
|
||||
name: wifi
|
||||
display_name: Enable Wi-Fi via the esp-wifi crate.
|
||||
help: esp-wifi comes with no stability guarantees at this time.
|
||||
requires:
|
||||
- alloc
|
||||
- unstable-hal
|
||||
chips:
|
||||
- esp32
|
||||
- esp32c2
|
||||
- esp32c3
|
||||
- esp32c6
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
|
||||
- !Option
|
||||
name: ble
|
||||
display_name: Enable BLE via the esp-wifi crate.
|
||||
help: esp-wifi comes with no stability guarantees at this time.
|
||||
requires:
|
||||
- alloc
|
||||
- unstable-hal
|
||||
chips:
|
||||
- esp32
|
||||
- esp32c2
|
||||
- esp32c3
|
||||
- esp32c6
|
||||
- esp32h2
|
||||
- esp32s3
|
||||
|
||||
- !Option
|
||||
name: embassy
|
||||
display_name: Add embassy framework support.
|
||||
help: esp-hal-embassy comes with no stability guarantees at this time.
|
||||
requires:
|
||||
- unstable-hal
|
||||
|
||||
- !Option
|
||||
name: probe-rs
|
||||
display_name: Use probe-rs to flash and monitor instead of espflash.
|
||||
help: probe-rs is a debugger that connects to the chips over JTAG. It can be used to flash and
|
||||
monitor, and it can also be used to interactively debug an application, or run tests on the
|
||||
hardware. Semihosting or RTT-based technologies like defmt-rtt require probe-rs.
|
||||
chips:
|
||||
- esp32c6
|
||||
- esp32h2
|
||||
- esp32s3
|
||||
|
||||
- !Option
|
||||
name: probe-rs
|
||||
display_name: Use probe-rs to flash and monitor instead of espflash.
|
||||
help: probe-rs is a debugger that connects to the chips over JTAG. It can be used to flash and
|
||||
monitor, and it can also be used to interactively debug an application, or run tests on the
|
||||
hardware. Semihosting or RTT-based technologies like defmt-rtt require probe-rs.
|
||||
|
||||
probe-rs requires a debug probe like esp-prog, and will not work with USB-UART adapters that
|
||||
often come on development boards.
|
||||
chips:
|
||||
- esp32
|
||||
- esp32s2
|
||||
- esp32c2
|
||||
- esp32c3
|
||||
|
||||
- !Category
|
||||
name: flashing-probe-rs
|
||||
display_name: Flashing, logging and debugging (probe-rs)
|
||||
requires:
|
||||
- probe-rs
|
||||
options:
|
||||
- !Option
|
||||
name: defmt
|
||||
display_name: Use defmt to print messages.
|
||||
selection_group: log-frontend
|
||||
- !Option
|
||||
name: panic-rtt-target
|
||||
display_name: Use panic-rtt-target as the panic handler.
|
||||
selection_group: panic-handler
|
||||
requires:
|
||||
- probe-rs
|
||||
|
||||
- !Category
|
||||
name: flashing-espflash
|
||||
display_name: Flashing, logging and debugging (espflash)
|
||||
requires:
|
||||
- "!probe-rs"
|
||||
options:
|
||||
- !Option
|
||||
name: log
|
||||
display_name: Use the log crate to print messages.
|
||||
selection_group: log-frontend
|
||||
requires:
|
||||
- "!probe-rs"
|
||||
- !Option
|
||||
name: defmt
|
||||
display_name: Use defmt to print messages.
|
||||
selection_group: log-frontend
|
||||
- !Option
|
||||
name: esp-backtrace
|
||||
display_name: Use esp-backtrace as the panic handler.
|
||||
selection_group: panic-handler
|
||||
requires:
|
||||
- "!probe-rs"
|
||||
|
||||
- !Category
|
||||
name: optional
|
||||
display_name: Options
|
||||
options:
|
||||
- !Option
|
||||
name: wokwi
|
||||
display_name: Add support for Wokwi simulation using VS Code Wokwi extension.
|
||||
chips:
|
||||
- esp32
|
||||
- esp32c3
|
||||
- esp32c6
|
||||
- esp32h2
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
|
||||
- !Option
|
||||
name: dev-container
|
||||
display_name: Add support for VS Code Dev Containers and GitHub Codespaces.
|
||||
|
||||
- !Option
|
||||
name: ci
|
||||
display_name: Add GitHub Actions support with some basic checks.
|
||||
|
||||
- !Category
|
||||
name: editor
|
||||
display_name: Optional editor config files for rust-analyzer
|
||||
options:
|
||||
- !Option
|
||||
name: helix
|
||||
display_name: Add rust-analyzer settings for Helix Editor
|
||||
|
||||
- !Option
|
||||
name: vscode
|
||||
display_name: Add rust-analyzer settings for Visual Studio Code
|
||||
Reference in New Issue
Block a user