#![no_std] #![no_main] extern crate alloc; mod strip; mod map; mod commands; mod animations; mod constants; use alloc::boxed::Box; use embedded_hal::serial::{Read, Write}; use embedded_hal::timer::CountDown; use esp_backtrace as _; use esp_println::println; use hal::{clock::ClockControl, peripherals::Peripherals, prelude::*, timer::{TimerGroup}, Rtc, IO, Delay, PulseControl, Uart}; use hal::uart::config::{Config, DataBits, Parity, StopBits}; use hal::uart::TxRxPins; use nb::block; use nb::Error::{Other}; use smart_leds::{RGB8, SmartLedsWrite}; use esp_alloc::EspHeap; use crate::animations::animation_manager::AnimationManager; use crate::commands::all_command::AllCommand; use crate::commands::command_handler::{CommandHandler}; use crate::commands::command_handler; use crate::commands::hello_world_command::HelloWorldCommand; use crate::commands::reset_command::ResetCommand; use crate::commands::set_command::SetCommand; use crate::commands::snake_command::SnakeCommand; use crate::map::Map; use crate::strip::StripTiming; #[global_allocator] static ALLOCATOR: EspHeap = EspHeap::empty(); fn init_heap() { extern "C" { static mut _heap_start: u32; static mut _heap_end: u32; } unsafe { let heap_start = &_heap_start as *const _ as usize; let heap_end = &_heap_end as *const _ as usize; ALLOCATOR.init(heap_start as *mut u8, heap_end - heap_start); } } #[entry] fn main() -> ! { let peripherals = Peripherals::take(); let mut system = peripherals.DPORT.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); init_heap(); // Disable the RTC and TIMG watchdog timers let mut rtc = Rtc::new(peripherals.RTC_CNTL); let timer_group0 = TimerGroup::new( peripherals.TIMG0, &clocks, &mut system.peripheral_clock_control, ); let mut wdt0 = timer_group0.wdt; let timer_group1 = TimerGroup::new( peripherals.TIMG1, &clocks, &mut system.peripheral_clock_control, ); let mut wdt1 = timer_group1.wdt; rtc.rwdt.disable(); wdt0.disable(); wdt1.disable(); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); // Init UART let pins = TxRxPins::new_tx_rx( io.pins.gpio1.into_push_pull_output(), io.pins.gpio3.into_floating_input(), ); let config = Config { baudrate: 115200, data_bits: DataBits::DataBits8, parity: Parity::ParityNone, stop_bits: StopBits::STOP1, }; let mut serial = Uart::new_with_config( peripherals.UART0, Some(config), Some(pins), &clocks, &mut system.peripheral_clock_control, ); // Init strip let pulse = PulseControl::new( peripherals.RMT, &mut system.peripheral_clock_control, ).unwrap(); let mut strip = strip::Strip::<_, { constants::LEDS_COUNT * 24 + 1 }>::new( pulse.channel0, io.pins.gpio25, StripTiming::new( 800u32.nanos(), 450u32.nanos(), 400u32.nanos(), 850u32.nanos(), ), ); // Init map let mut rgb_data: [RGB8; 72] = [RGB8 { r: 0, g: 0, b: 0 }; 72]; let mut map = map::Map::new(&map::INDEX_MAP, &mut rgb_data); let mut animations = AnimationManager::new(timer_group0.timer0); let mut delay = Delay::new(&clocks); // Init commands let mut handler = CommandHandler::new( [ ("HELLO_WORLD", Box::new(HelloWorldCommand::default())), ("SET", Box::new(SetCommand::default())), ("RESET", Box::new(ResetCommand::default())), ("ALL", Box::new(AllCommand::default())), ("SNAKE", Box::new(SnakeCommand::default())) ], ['\0'; constants::COMMAND_BUFFER], ); print_new_command(&mut serial); loop { // result is either ok, then do nothing, // would block, then do nothing // or last step, then do nothing as well... let _ = animations.update(&mut map); let new_command = match handler.read_command(&mut serial) { Ok(()) => { println!("\r"); let result = handler.handle_command(&mut map, animations.storage()); match result { Ok(()) => true, Err(err) => { match err { command_handler::CommandHandleError::NotFound => println!("Command not found.\r"), command_handler::CommandHandleError::WrongArguments => println!("Wrong arguments.\r"), command_handler::CommandHandleError::CommandNotRead => println!("FATAL: Command is not prepared.\r") } true } } }, Err(err) => { match err { Other(error) => { match error { command_handler::CommandReadError::BufferOverflowed => println!("Command is too long.\r"), command_handler::CommandReadError::UnexpectedEndOfLine => (), command_handler::CommandReadError::CommandLoadedAlready => println!("FATAL: Previous command not processed correctly.\r") }; true } _ => false } } }; if new_command { print_new_command(&mut serial); } strip.write(map.get_map().cloned()).unwrap(); delay.delay_us(500u32); } fn print_new_command>(serial: &mut T) { println!("\r"); block!(serial.write(b'>')).ok().unwrap(); block!(serial.write(b' ')).ok().unwrap(); } }