Успадкування часу від KeiraOS
Припустимо, прошивка запускається як .bin з Keira. У Keira вже є правильний час, і тягнути ще один Wi-Fi стек тільки заради дати файла якось не хочеться. Для цього в LilkaOxide є окремий feature keira-rtc.
Як це взагалі працює
MultiBoot записує застосунок в OTA-розділ і робить програмне перезавантаження. RTC ESP32-S3 при цьому продовжує рахувати час, а ESP-IDF залишає основу Unix-часу в регістрах STORE2/STORE3.
KeiraClock читає цей час через esp-hal, перевіряє допустимий діапазон і далі відраховує його від монотонного таймера. Він не викликає функції всередині Keira, не підключає ESP-IDF та нічого не записує в RTC.
Це не заміна синхронізації
Перед запуском потрібен правильний час у Keira: підключіться до Wi-Fi та дочекайтесь синхронізації її годинника. Після повного вимкнення живлення час може бути втрачений. Також важливі налаштування RTC у конкретній збірці Keira/ESP-IDF; передачу часу потрібно перевірити на пристрої.
Вмикаємо feature
До вже обраних features свого проєкту додаємо keira-rtc. Наприклад:
lilkaoxide = { path = "../../sdk-hal", default-features = false, features = [
"blocking", "RefCellBus", "display_buffer_1024", "alloc", "keira-rtc",
] }
За замовчуванням цього feature немає. Сам він не вмикає alloc, async, radio чи додаткові залежності. alloc у цьому прикладі належить базовій конфігурації прошивки, а не RTC API.
Мінімальний виклик
Після Lilka::init(...):
use lilkaoxide::{hal::rtc_cntl::Rtc, keira_rtc::KeiraClock};
let rtc = Rtc::new(lilka.peripherals.LPWR);
match KeiraClock::inherit(&rtc) {
Ok(clock) => {
let seconds = clock.now_unix_seconds().expect("Clock out of range");
esp_println::println!("UTC Unix time: {}", seconds);
}
Err(error) => {
esp_println::println!("Time unavailable: {}", error);
}
}
clock можна зберігати й опитувати протягом роботи програми. Після зняття початкового значення він вже не позичає rtc. Для async-прошивки відрізняється ініціалізація Lilka через .await, а саме RTC API залишається таким самим.
Що повертає API
KeiraClock::inherit(&rtc)—Result, а не безумовно правильний час.now_unix_micros()— UTC timestamp у мікросекундах.now_unix_seconds()— той самий час у цілих секундах.RtcTimeError::NotSynchronized— початкове значення не потрапило в діапазон 2020–2107.MonotonicWentBackwardsтаOutOfRange— порушення відліку або вихід за допустимі межі.
UTC і київський час — різні речі
SDK не додає дві чи три години й не тягне базу часових поясів. Для годинника або FAT-дат конвертуйте UTC вже в застосунку. Якщо потрібен часовий пояс, враховуйте не тільки зсув UTC, а й перехід на літній час. Для FAT реалізуйте embedded_sdmmc::TimeSource, який повертає вже потрібну календарну дату.
Перевірка діапазону відсікає незаданий годинник і очевидне сміття. Але вона не доводить, що час сьогодні правильний, або що його виставила саме Keira. Якщо інша ESP-IDF прошивка залишила правдоподібне, але неправильне значення, SDK цього сам не дізнається.
Повний приклад
examples/keira-clock/ показує UTC timestamp на дисплеї або підказує повернутись у Keira й синхронізувати годинник:
#![no_std]
#![no_main]
use core::fmt::Write;
use embedded_graphics::{
mono_font::{MonoTextStyle, ascii::FONT_6X10},
pixelcolor::Rgb565,
prelude::*,
text::{Baseline, Text},
};
use esp_println::{self as _, println};
use lilkaoxide::{keira_rtc::KeiraClock, prelude::*};
esp_bootloader_esp_idf::esp_app_desc!();
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
println!("PANIC: {}", info);
loop {
core::hint::spin_loop();
}
}
#[esp_hal::main]
fn main() -> ! {
esp_alloc::heap_allocator!(size: 16 * 1024);
let mut config = Configuration::default();
config.buzzer_config.duty_pct = 0;
let lilka = Lilka::init(config).expect("Lilka init failed");
let rtc = esp_hal::rtc_cntl::Rtc::new(lilka.peripherals.LPWR);
let clock = KeiraClock::inherit(&rtc);
let mut display = lilka.display;
let delay = esp_hal::delay::Delay::new();
loop {
let mut message: heapless::String<96> = heapless::String::new();
match &clock {
Ok(clock) => match clock.now_unix_seconds() {
Ok(seconds) => {
let _ = write!(message, "UTC Unix seconds:\n{}", seconds);
}
Err(error) => {
let _ = write!(message, "Clock error:\n{}", error);
}
},
Err(_) => {
let _ = message.push_str(concat!(
"Time unavailable.\n",
"Sync clock in Keira via Wi-Fi,\n",
"then launch this .bin again."
));
}
}
display.clear(Rgb565::BLACK).unwrap();
Text::with_baseline(
&message,
Point::new(8, 24),
MonoTextStyle::new(&FONT_6X10, Rgb565::CYAN),
Baseline::Top,
)
.draw(&mut display)
.unwrap();
delay.delay_millis(1000);
}
}
З цієї теки створіть .bin:
Після цього відкрийте його на microSD через Keira. Rustdoc API містить ті самі методи з їх типами та обмеженнями.