diff --git a/src/drivers/rtc.rs b/src/drivers/rtc.rs index c7f4cb4..14162d4 100644 --- a/src/drivers/rtc.rs +++ b/src/drivers/rtc.rs @@ -1,108 +1,164 @@ -use embassy_time::{Duration, Timer}; -use log::info; +use core::time; + +use chrono::NaiveDate; +use ds3231::{ + Alarm1Config, Config, DS3231, DS3231Error, InterruptControl, Oscillator, Seconds, + SquareWaveFrequency, TimeRepresentation, +}; +use embassy_time::{Duration, Timer, WithTimeout}; +use esp_hal::{ + Async, + i2c::{self, master::I2c}, + peripherals, +}; +use log::{debug, error, info}; + +use crate::{FEEDBACK_STATE, UTC_TIME, drivers, feedback, init}; +use chrono::{NaiveDateTime, TimeZone, Utc}; + +include!(concat!(env!("OUT_DIR"), "/build_time.rs")); + +const RTC_ADDRESS: u8 = 0x68; #[embassy_executor::task] -pub async fn rtc_task() { - info!("RTC task started"); - // Initialize I2C and RTC here +pub async fn rtc_task( + i2c: i2c::master::I2c<'static, Async>, + sqw_pin: peripherals::GPIO21<'static>, +) { + UTC_TIME.signal(BUILD_UNIX_TIME); + info!("Build time: {}", BUILD_UNIX_TIME); + // i2c.write_async(RTC_ADDRESS, &[0x0E, 0b00000000]) // Clear control register + // .await + // .unwrap_or_else(|e| { + // FEEDBACK_STATE.signal(feedback::FeedbackState::Error); + // error!("Failed to clear RTC control register: {:?}", e); + // }); + + // debug!("init rtc interrupt"); + // let mut rtc_interrupt = init::hardware::setup_rtc_iterrupt(sqw_pin).await; + + debug!("configuring rtc"); + let mut rtc = drivers::rtc::rtc_config(i2c).await; + + debug!("rtc up"); loop { - // Read RTC time and update UTC_TIME signal - // let utc_time = read_rtc_time(&mut rtc).await.unwrap(); - // UTC_TIME.signal(utc_time); + //set_rtc_alarm(&mut rtc).await; + // debug!("Waiting for RTC interrupt..."); + // rtc_interrupt.wait_for_falling_edge().await; + // debug!("RTC interrupt triggered"); - // Simulate waiting for an interrupt or event Timer::after(Duration::from_millis(1000)).await; - info!("RTC tick"); + //TODO use pub sub channel or something similar to send the time when needed + let timestamp = drivers::rtc::read_rtc_time(&mut rtc).await; + match timestamp { + Ok(ts) => { + UTC_TIME.signal(ts); + info!("Current UTC time: {}", UTC_TIME.wait().await); + } + Err(e) => { + FEEDBACK_STATE.signal(feedback::FeedbackState::Error); + error!("Failed to read RTC datetime: {:?}", e); + } + } } } +pub async fn rtc_config(i2c: I2c<'static, Async>) -> DS3231> { + let mut rtc: DS3231> = DS3231::new(i2c, RTC_ADDRESS); + let naive_dt = Utc + .timestamp_opt(BUILD_UNIX_TIME as i64, 0) + .single() + .unwrap() + .naive_utc(); + + let rtc_config = Config { + time_representation: TimeRepresentation::TwentyFourHour, + square_wave_frequency: SquareWaveFrequency::Hz1, + interrupt_control: InterruptControl::Interrupt, // Enable interrupt mode + battery_backed_square_wave: false, + oscillator_enable: Oscillator::Disabled, + }; + + match rtc.configure(&rtc_config).await { + Ok(_) => info!("DS3231 configured successfully"), + Err(e) => { + info!("Failed to configure DS3231: {:?}", e); + panic!("DS3231 configuration failed"); + } + } + + rtc.set_datetime(&naive_dt).await.unwrap_or_else(|e| { + FEEDBACK_STATE.signal(feedback::FeedbackState::Error); + error!("Failed to set RTC datetime: {:?}", e); + }); + info!("RTC datetime set to: {}", naive_dt); + match rtc.status().await { + Ok(mut status) => { + status.set_alarm1_flag(false); + status.set_alarm2_flag(false); + match rtc.set_status(status).await { + Ok(_) => info!("Alarm flags cleared"), + Err(e) => info!("Failed to clear alarm flags: {:?}", e), + } + } + Err(e) => info!("Failed to read status: {:?}", e), + } + + rtc +} +pub async fn read_rtc_time<'a>( + rtc: &'a mut DS3231>, +) -> Result> { + let timestamp_result = rtc.datetime().await?; + Ok(timestamp_result.and_utc().timestamp() as u64) +} - - -/* ************************************************************************************** */ - - -// use ds3231::{Alarm1Config, DS3231, DS3231Error, Seconds}; -// use embassy_time::{Duration, Timer}; -// use esp_hal::{ -// Async, -// i2c::{self, master::I2c}, -// peripherals, -// }; -// use log::{debug, error, info}; - -// use crate::{UTC_TIME, drivers, init}; - -// const RTC_ADDRESS: u8 = 0x57; - -// #[embassy_executor::task] -// pub async fn rtc_task( -// //i2c: i2c::master::I2c<'static, Async>, -// //sqw_pin: peripherals::GPIO21<'static>, -// ) { -// //UTC_TIME.signal(155510); - -// // debug!("init rtc interrupt"); -// // let mut rtc_interrupt = init::hardware::setup_rtc_iterrupt(sqw_pin).await; -// // debug!("configuring rtc"); -// // let mut rtc = drivers::rtc::rtc_config(i2c).await; - -// // let timestamp_result = drivers::rtc::read_rtc_time(&mut rtc).await; -// // UTC_TIME.signal(timestamp_result.unwrap()); - -// debug!("rtc up"); -// loop { -// info!("Current UTC time: {}", UTC_TIME.wait().await); -// // debug!("Waiting for RTC interrupt..."); -// // rtc_interrupt.wait_for_falling_edge().await; -// // debug!("RTC interrupt triggered"); -// // let timestamp_result = drivers::rtc::read_rtc_time(&mut rtc).await; -// // UTC_TIME.signal(timestamp_result.unwrap()); -// // Timer::after(Duration::from_secs(1)).await; // Debounce delay -// } -// } - -// pub async fn rtc_config(i2c: I2c<'static, Async>) -> DS3231> { -// let mut rtc: DS3231> = DS3231::new(i2c, RTC_ADDRESS); -// let daily_alarm = Alarm1Config::AtTime { -// hours: 0, // set alarm every day 00:00:00 to sync time -// minutes: 0, -// seconds: 10, -// is_pm: None, // 24-hour mode -// }; - - // let naive_dt = chrono::NaiveDateTime::from_timestamp_opt(*utc_time as i64, 0) - // .expect("Invalid timestamp for NaiveDateTime"); - // rtc.set_datetime(&naive_dt).await.unwrap_or_else(|e| { - // error!("Failed to set RTC datetime: {:?}", e); - // panic!(); - // }); - - // if let Err(e) = rtc.set_alarm1(&daily_alarm).await { - // error!("Failed to configure RTC: {:?}", e); - // panic!(); - // } -// rtc -// } - -// pub async fn read_rtc_time<'a>( -// rtc: &'a mut DS3231>, -// ) -> Result> { // match rtc.datetime().await { // Ok(datetime) => { // let utc_time = datetime.and_utc().timestamp() as u64; // Ok(utc_time) // } // Err(e) => { +// FEEDBACK_STATE.signal(feedback::FeedbackState::Error); // error!("Failed to read RTC datetime: {:?}", e); // Err(e) // } // } +// } + + // let alarm_config = Alarm1Config::AtSeconds { seconds: 0}; + + // match rtc.set_alarm1(&alarm_config).await { + // Ok(_) => info!("Alarm 1 set to trigger at seconds"), + // Err(e) => { + // FEEDBACK_STATE.signal(feedback::FeedbackState::Error); + // error!("Failed to set Alarm 1: {:?}", e); + // } + // } + +/* ************************************************************************************** */ + +// #[embassy_executor::task] +// pub async fn rtc_task() { +// info!("RTC task started"); +// // Initialize I2C and RTC here + +// loop { +// // Read RTC time and update UTC_TIME signal +// // let utc_time = read_rtc_time(&mut rtc).await.unwrap(); +// // UTC_TIME.signal(utc_time); + +// // Simulate waiting for an interrupt or event +// Timer::after(Duration::from_millis(1000)).await; +// info!("RTC tick"); +// } +// } + // } // TODO Update time when device is connected other device over Wifi diff --git a/src/feedback.rs b/src/feedback.rs index 93accfb..111e106 100644 --- a/src/feedback.rs +++ b/src/feedback.rs @@ -35,7 +35,15 @@ pub async fn feedback_task(buzzer: peripherals::GPIO19<'static>) { Timer::after(Duration::from_millis(100)).await; buzzer.set_low(); } - FeedbackState::Error => {} + FeedbackState::Error => { + buzzer.set_high(); + Timer::after(Duration::from_millis(500)).await; + buzzer.set_low(); + Timer::after(Duration::from_millis(500)).await; + buzzer.set_high(); + Timer::after(Duration::from_millis(500)).await; + buzzer.set_low(); + } FeedbackState::Startup => { buzzer.set_high(); Timer::after(Duration::from_millis(10)).await; diff --git a/src/main.rs b/src/main.rs index 381c7ca..238854e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,11 +3,10 @@ #![feature(type_alias_impl_trait)] #![feature(impl_trait_in_assoc_type)] -use esp_alloc::EspHeap; use embassy_executor::Spawner; use embassy_net::Stack; use embassy_sync::{ - blocking_mutex::raw::{NoopRawMutex, CriticalSectionRawMutex}, + blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}, pubsub::{ PubSubChannel, Publisher, WaitResult::{Lagged, Message}, @@ -15,19 +14,18 @@ use embassy_sync::{ signal::Signal, }; use embassy_time::{Duration, Timer}; +use esp_alloc::EspHeap; use log::{debug, info}; use static_cell::make_static; use crate::{store::TallyID, webserver::start_webserver}; -mod init; mod drivers; mod feedback; +mod init; mod store; mod webserver; -include!(concat!(env!("OUT_DIR"), "/build_time.rs")); - static UTC_TIME: Signal = Signal::new(); static FEEDBACK_STATE: Signal = Signal::new(); @@ -36,7 +34,6 @@ type TallyPublisher = Publisher<'static, NoopRawMutex, TallyID, 8, 2, 1>; #[esp_hal_embassy::main] async fn main(mut spawner: Spawner) { - let (uart_device, stack, _i2c, sqw_pin, buzzer_gpio) = init::hardware::hardware_init(&mut spawner).await; @@ -58,7 +55,7 @@ async fn main(mut spawner: Spawner) { )); debug!("spawing rtc task"); - spawner.must_spawn(drivers::rtc::rtc_task()); + spawner.must_spawn(drivers::rtc::rtc_task(_i2c, sqw_pin)); debug!("spawing feedback task.."); spawner.must_spawn(feedback::feedback_task(buzzer_gpio)); @@ -66,13 +63,11 @@ async fn main(mut spawner: Spawner) { let mut sub = chan.subscriber().unwrap(); - - debug!("everythig spwawned"); + debug!("everything spawned"); FEEDBACK_STATE.signal(feedback::FeedbackState::Startup); loop { - - info!("runnung in main loop"); + info!("running in main loop"); Timer::after(Duration::from_millis(1000)).await; // let wait_result = sub.next_message().await; // match wait_result {