Improve visuals and animation

This commit is contained in:
Mona Mayrhofer 2025-06-27 22:23:01 +02:00
parent 654bd8bdf6
commit 700bc71bf6
No known key found for this signature in database
GPG key ID: 3E2BDA732A957188
3 changed files with 124 additions and 65 deletions

1
Cargo.lock generated
View file

@ -900,6 +900,7 @@ dependencies = [
"esp-println",
"esp-wifi",
"heapless",
"libm",
"log",
"smart-leds",
"smoltcp",

View file

@ -66,6 +66,7 @@ smart-leds = "0.4.0"
ws2812-spi = "0.5.0"
embassy-futures = "0.1.1"
embassy-sync = "0.7.0"
libm = "0.2.15"
[profile.dev]
# Rust debug is too slow.

View file

@ -1,20 +1,28 @@
#![no_std]
#![no_main]
use alloc::boxed::Box;
use core::ops::BitXor;
use core::ops::Rem;
use core::pin::Pin;
use embassy_executor::Spawner;
use embassy_futures::select::{Either, select};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::channel::{Channel, Sender};
use embassy_sync::mutex::Mutex;
use embassy_sync::watch::{self, Watch};
use embassy_time::{Duration, Instant, Timer, WithTimeout};
use esp_hal::clock::CpuClock;
use esp_hal::gpio::{Input, InputConfig, Pull};
use esp_hal::gpio::{DriveMode, Input, InputConfig, Pull};
use esp_hal::peripherals::GPIO;
use esp_hal::rng;
use esp_hal::spi::master::{Config, Spi};
use esp_hal::time::Rate;
use esp_hal::timer::systimer::SystemTimer;
use esp_hal::timer::timg::TimerGroup;
use esp_hal::{Async, Blocking, DriverMode};
use libm::sin;
use log::info;
use smart_leds::RGB8;
use smart_leds::SmartLedsWrite;
@ -28,11 +36,30 @@ fn panic(_: &core::panic::PanicInfo) -> ! {
extern crate alloc;
#[derive(Clone, Debug, PartialEq, Eq)]
struct TargetState {
enabled: [bool; 12],
}
impl Default for TargetState {
fn default() -> Self {
TargetState {
enabled: [false; 12],
}
}
}
static CHANNEL: StaticCell<Channel<NoopRawMutex, i32, 2>> = StaticCell::new();
static STATE: Mutex<CriticalSectionRawMutex, TargetState> = Mutex::new(TargetState {
enabled: [false; 12],
});
const ORDER: [usize; 12] = [5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11];
#[esp_hal_embassy::main]
async fn main(spawner: Spawner) {
let channel = CHANNEL.init(Channel::new());
//let state_watch = STATE.init(Arc::new(Mutex::new(TargetState::default())));
// generator version: 0.3.1
esp_println::logger::init_logger_from_env();
@ -55,23 +82,7 @@ async fn main(spawner: Spawner) {
)
.unwrap();
spawner
.spawn(listen_rotary_encoder(
RotaryEncoderConfig {
clk: Input::new(
peripherals.GPIO8,
InputConfig::default().with_pull(Pull::Up),
),
ot: Input::new(
peripherals.GPIO10,
InputConfig::default().with_pull(Pull::Up),
),
},
channel.sender(),
))
.unwrap();
let mut led_strip = {
let led_strip = {
let spi = Spi::new(
peripherals.SPI2,
Config::default().with_frequency(Rate::from_mhz(3)),
@ -81,56 +92,35 @@ async fn main(spawner: Spawner) {
Ws2812::new(spi)
};
let colors = [
RGB8 { r: 0, g: 255, b: 0 },
RGB8 { r: 255, g: 0, b: 0 },
RGB8 { r: 255, g: 0, b: 0 },
RGB8 {
r: 0,
g: 255,
b: 255,
},
RGB8 {
r: 255,
g: 0,
b: 255,
},
RGB8 {
r: 255,
g: 255,
b: 0,
},
];
let mut color_idx = 0;
let encoder = RotaryEncoderConfig {
clk: Input::new(
peripherals.GPIO8,
InputConfig::default().with_pull(Pull::Up),
),
ot: Input::new(
peripherals.GPIO10,
InputConfig::default().with_pull(Pull::Up),
),
};
spawner
.spawn(listen_rotary_encoder(encoder, channel.sender()))
.unwrap();
spawner.spawn(render_gems(led_strip)).unwrap();
let mut state = TargetState::default();
let mut cnt = 0;
loop {
let delta = channel.receive().await;
color_idx += delta;
// led_strip
// .write([
// colors[color_idx % colors.len()],
// colors[(color_idx + 1) % colors.len()],
// colors[(color_idx + 2) % colors.len()],
// colors[(color_idx + 3) % colors.len()],
// ])
// .unwrap();
//
cnt = (cnt + delta).clamp(0, 12);
let cnt = 12;
led_strip
.write((0..cnt).map(|it| {
if it <= (color_idx % cnt) {
RGB8 {
r: 255,
g: 50,
b: 00,
state.enabled = [false; 12];
for i in (0..12) {
state.enabled[ORDER[i]] = (cnt > i as i32);
}
} else {
RGB8 { r: 0, g: 0, b: 0 }
{
let mut state_lock = STATE.lock().await;
*state_lock = state.clone();
}
}))
.unwrap();
}
// 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
@ -153,6 +143,73 @@ enum RotaryDirection {
Ccw,
}
#[embassy_executor::task]
async fn render_gems(
mut strip: Ws2812<Spi<'static, Blocking>>,
//target: Mutex<NoopRawMutex, TargetState>,
) {
let mut temp = [0.0f32; 12];
let mut last_state = TargetState::default();
let mut frame = 0usize;
loop {
frame = frame.wrapping_add(1);
{
let target = STATE.lock().await;
for i in (0..12) {
if target.enabled[i] && !last_state.enabled[i] {
temp[i] = 3.0;
} else {
let trg = if target.enabled[i] { 1.0 } else { 0.0 };
let speed = ((temp[i] - trg).abs() * 0.2).clamp(0.1, 0.5);
if temp[i] < trg {
temp[i] = (temp[i] + speed).min(trg);
} else {
temp[i] = (temp[i] - speed).max(trg);
}
}
}
last_state = target.clone();
}
strip
.write(temp.iter().enumerate().map(|(index, it)| {
let temp = *it;
// let temp = *it
// + (((sin(
// //(index.wrapping_mul(182945).bitxor(48194291).rem(100) as f64) +
// (frame as f64 * 0.05),
// ) as f32)
// / 2.0
// + 0.5)
// * 0.1);
let green_tint = 20.0;
if temp > 1.0 {
RGB8 {
r: 255u8,
g: (50.0 + (255.0 - 50.0) * (temp - 1.0)) as u8,
b: (255.0 * (temp - 1.0)) as u8,
}
} else {
RGB8 {
r: (255.0 * temp) as u8,
g: (green_tint * temp) as u8,
b: (20.0 * (1.0 - temp)) as u8,
}
}
}))
.unwrap();
Timer::after_millis(1000 / 24).await;
}
}
#[embassy_executor::task]
async fn listen_rotary_encoder(
mut config: RotaryEncoderConfig<'static, 'static>,