1#![allow(missing_docs)]
2#![cfg(feature = "wifi")]
5#![no_std]
6#![no_main]
7#![allow(clippy::future_not_send, reason = "single-threaded")]
8
9use core::{convert::Infallible, fmt};
10use defmt::*;
11use defmt_rtt as _;
12use device_envoy::button::PressedTo;
13use device_envoy::char_lcd::{CharLcd, CharLcdStatic};
14use device_envoy::clock_sync::{ClockSync, ClockSyncStatic, ONE_SECOND};
15use device_envoy::flash_array::FlashArray;
16use device_envoy::wifi_auto::WifiAuto;
17use device_envoy::wifi_auto::fields::{TimezoneField, TimezoneFieldStatic};
18use device_envoy::{Error, Result};
19use embassy_executor::Spawner;
20use heapless::String;
21use panic_probe as _;
22
23#[embassy_executor::main]
28pub async fn main(spawner: Spawner) -> ! {
29 let err = inner_main(spawner).await.unwrap_err();
31 core::panic!("{err}");
32}
33
34async fn inner_main(spawner: Spawner) -> Result<Infallible> {
35 info!("Starting LCD Clock with WiFi");
36
37 let p = embassy_rp::init(Default::default());
39
40 static CHAR_LCD_STATIC: CharLcdStatic = CharLcd::new_static();
42 let char_lcd = CharLcd::new(&CHAR_LCD_STATIC, p.I2C0, p.PIN_5, p.PIN_4, spawner)?;
43
44 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
46
47 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
49 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
50
51 let wifi_auto = WifiAuto::new(
53 p.PIN_23, p.PIN_24, p.PIN_25, p.PIN_29, p.PIO0, p.DMA_CH0, wifi_credentials_flash_block,
60 p.PIN_13, PressedTo::Ground,
62 "www.picoclock.net",
63 [timezone_field],
64 spawner,
65 )?;
66
67 let (stack, _button) = wifi_auto.connect(|_event| async move { Ok(()) }).await?;
69
70 let timezone_offset_minutes = timezone_field
72 .offset_minutes()?
73 .ok_or(Error::MissingCustomWifiAutoField)?;
74 static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
75 let clock_sync = ClockSync::new(
76 &CLOCK_SYNC_STATIC,
77 stack,
78 timezone_offset_minutes,
79 Some(ONE_SECOND),
80 spawner,
81 );
82
83 info!("Entering main event loop");
84
85 loop {
87 let tick = clock_sync.wait_for_tick().await;
88 let time_info = tick.local_time;
89 let mut text = String::<64>::new();
90 let (hour12, am_pm) = if time_info.hour() == 0 {
91 (12, "AM")
92 } else if time_info.hour() < 12 {
93 (time_info.hour(), "AM")
94 } else if time_info.hour() == 12 {
95 (12, "PM")
96 } else {
97 #[expect(clippy::arithmetic_side_effects, reason = "hour guaranteed 13-23")]
98 {
99 (time_info.hour() - 12, "PM")
100 }
101 };
102 fmt::Write::write_fmt(
103 &mut text,
104 format_args!(
105 "{:2}:{:02}:{:02} {}\n{:04}-{:02}-{:02}",
106 hour12,
107 time_info.minute(),
108 time_info.second(),
109 am_pm,
110 time_info.year(),
111 u8::from(time_info.month()),
112 time_info.day()
113 ),
114 )
115 .map_err(|_| Error::FormatError)?;
116 char_lcd.write_text(text, 0).await;
117 }
118}