pub struct ClockSync { /* private fields */ }wifi and non-crate feature host only.Expand description
Combines NTP synchronization with a local clock and tick events.
ClockSync does not emit ticks until the first successful sync (or a manual
call to ClockSync::set_utc_time). Each tick includes how long it has been
since the last successful sync.
§Example: WiFi + ClockSync logging
use device_envoy::{
Error,
Result,
button::PressedTo,
clock_sync::{ClockSync, ClockSyncStatic, ONE_SECOND, h12_m_s},
flash_array::FlashArray,
wifi_auto::fields::{TimezoneField, TimezoneFieldStatic},
wifi_auto::{WifiAuto, WifiAutoEvent},
};
use defmt::info;
async fn run(
spawner: embassy_executor::Spawner,
p: embassy_rp::Peripherals,
) -> Result<(), device_envoy::Error> {
let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
static TIMEZONE_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
let timezone_field = TimezoneField::new(&TIMEZONE_STATIC, timezone_flash_block);
let wifi_auto = WifiAuto::new(
p.PIN_23,
p.PIN_24,
p.PIN_25,
p.PIN_29,
p.PIO0,
p.DMA_CH0,
wifi_credentials_flash_block,
p.PIN_13,
PressedTo::Ground,
"ClockSync",
[timezone_field],
spawner,
)?;
let (stack, _button) = wifi_auto
.connect(|event| async move {
match event {
WifiAutoEvent::CaptivePortalReady => {
info!("WifiAuto: setup mode ready");
}
WifiAutoEvent::Connecting { .. } => {
info!("WifiAuto: connecting");
}
WifiAutoEvent::ConnectionFailed => {
info!("WifiAuto: connection failed");
}
}
Ok(())
})
.await?;
let offset_minutes = timezone_field
.offset_minutes()?
.ok_or(Error::MissingCustomWifiAutoField)?;
static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
let clock_sync = ClockSync::new(
&CLOCK_SYNC_STATIC,
stack,
offset_minutes,
Some(ONE_SECOND),
spawner,
);
loop {
let tick = clock_sync.wait_for_tick().await;
let (hours, minutes, seconds) = h12_m_s(&tick.local_time);
info!(
"Time {:02}:{:02}:{:02}, since sync {}s",
hours,
minutes,
seconds,
tick.since_last_sync.as_secs()
);
}
}Implementations§
Source§impl ClockSync
impl ClockSync
Sourcepub const fn new_static() -> ClockSyncStatic
pub const fn new_static() -> ClockSyncStatic
Create ClockSync resources.
Examples found in repository?
More examples
Sourcepub fn new(
clock_sync_static: &'static ClockSyncStatic,
stack: &'static Stack<'static>,
offset_minutes: i32,
tick_interval: Option<Duration>,
spawner: Spawner,
) -> Self
pub fn new( clock_sync_static: &'static ClockSyncStatic, stack: &'static Stack<'static>, offset_minutes: i32, tick_interval: Option<Duration>, spawner: Spawner, ) -> Self
Create a ClockSync using an existing network stack.
See the ClockSync struct example for usage.
Examples found in repository?
32async fn inner_main(spawner: Spawner) -> Result<Infallible> {
33 info!("Starting Console Clock with WiFi");
34
35 // Initialize RP2040 peripherals
36 let p = embassy_rp::init(Default::default());
37
38 // Use two blocks of flash storage: Wi-Fi credentials + timezone
39 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
40
41 // Define timezone field for captive portal
42 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
43 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
44
45 // Set up WiFi via captive portal
46 let wifi_auto = WifiAuto::new(
47 p.PIN_23, // CYW43 power
48 p.PIN_24, // CYW43 clock
49 p.PIN_25, // CYW43 chip select
50 p.PIN_29, // CYW43 data pin
51 p.PIO0, // CYW43 PIO interface
52 p.DMA_CH0, // CYW43 DMA channel
53 wifi_credentials_flash_block,
54 p.PIN_13, // Reset button pin
55 PressedTo::Ground,
56 "www.picoclock.net",
57 [timezone_field],
58 spawner,
59 )?;
60
61 // Connect to WiFi
62 let (stack, _button) = wifi_auto
63 .connect(|event| async move {
64 match event {
65 WifiAutoEvent::CaptivePortalReady => {
66 info!("Captive portal ready - connect to WiFi network");
67 }
68 WifiAutoEvent::Connecting {
69 try_index,
70 try_count,
71 } => {
72 info!(
73 "Connecting to WiFi (attempt {} of {})...",
74 try_index + 1,
75 try_count
76 );
77 }
78 WifiAutoEvent::ConnectionFailed => {
79 info!("WiFi connection failed!");
80 }
81 }
82 Ok(())
83 })
84 .await?;
85
86 info!("WiFi connected successfully!");
87
88 // Create ClockSync device with timezone from WiFi portal
89 let timezone_offset_minutes = timezone_field
90 .offset_minutes()?
91 .ok_or(Error::MissingCustomWifiAutoField)?;
92 static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
93 let clock_sync = ClockSync::new(
94 &CLOCK_SYNC_STATIC,
95 stack,
96 timezone_offset_minutes,
97 Some(ONE_SECOND),
98 spawner,
99 );
100
101 info!("WiFi connected, entering event loop");
102
103 // Main event loop - log time on every tick
104 loop {
105 let tick = clock_sync.wait_for_tick().await;
106 let time_info = tick.local_time;
107 info!(
108 "Current time: {:04}-{:02}-{:02} {:02}:{:02}:{:02}",
109 time_info.year(),
110 u8::from(time_info.month()),
111 time_info.day(),
112 time_info.hour(),
113 time_info.minute(),
114 time_info.second(),
115 );
116 }
117}More examples
34async fn inner_main(spawner: Spawner) -> Result<Infallible> {
35 info!("Starting LCD Clock with WiFi");
36
37 // Initialize RP2040 peripherals
38 let p = embassy_rp::init(Default::default());
39
40 // Initialize CharLcd
41 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 // Use two blocks of flash storage: Wi-Fi credentials + timezone
45 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
46
47 // Define timezone field for captive portal
48 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
49 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
50
51 // Set up WiFi via captive portal
52 let wifi_auto = WifiAuto::new(
53 p.PIN_23, // CYW43 power
54 p.PIN_24, // CYW43 clock
55 p.PIN_25, // CYW43 chip select
56 p.PIN_29, // CYW43 data pin
57 p.PIO0, // CYW43 PIO interface
58 p.DMA_CH0, // CYW43 DMA channel
59 wifi_credentials_flash_block,
60 p.PIN_13, // Reset button pin
61 PressedTo::Ground,
62 "www.picoclock.net",
63 [timezone_field],
64 spawner,
65 )?;
66
67 // Connect to WiFi
68 let (stack, _button) = wifi_auto.connect(|_event| async move { Ok(()) }).await?;
69
70 // Create ClockSync device with timezone from WiFi portal
71 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 // Main orchestrator loop - owns LCD and displays the clock
86 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}60async fn inner_main(spawner: Spawner) -> Result<Infallible> {
61 info!("Starting Wi-Fi servo clock (WifiAuto)");
62 let p = embassy_rp::init(Default::default());
63
64 // Use two blocks of flash storage: Wi-Fi credentials + timezone
65 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
66
67 // Define HTML to ask for timezone on the captive portal.
68 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
69 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
70
71 // Set up Wifi via a captive portal. The button pin is used to reset stored credentials.
72 let wifi_auto = WifiAuto::new(
73 p.PIN_23, // CYW43 power
74 p.PIN_24, // CYW43 clock
75 p.PIN_25, // CYW43 chip select
76 p.PIN_29, // CYW43 data pin
77 p.PIO0, // CYW43 PIO interface
78 p.DMA_CH0, // CYW43 DMA channel
79 wifi_credentials_flash_block,
80 p.PIN_13, // Reset button pin
81 PressedTo::Ground,
82 "PicoServoClock", // Captive-portal SSID
83 [timezone_field],
84 spawner,
85 )?;
86
87 // Configure two servos for the display.
88 let bottom_servo = BottomServoPlayer::new(p.PIN_11, p.PWM_SLICE5, spawner)?;
89 let top_servo = TopServoPlayer::new(p.PIN_12, p.PWM_SLICE6, spawner)?;
90 let servo_display = ServoClockDisplay::new(bottom_servo, top_servo);
91
92 // Connect Wi-Fi, using the servos for status indications.
93 let servo_display_ref = &servo_display;
94 let (stack, button) = wifi_auto
95 .connect(|event| {
96 let servo_display_ref = servo_display_ref;
97 async move {
98 match event {
99 WifiAutoEvent::CaptivePortalReady => {
100 servo_display_ref.show_portal_ready().await;
101 }
102 WifiAutoEvent::Connecting { .. } => servo_display_ref.show_connecting().await,
103 WifiAutoEvent::ConnectionFailed => {
104 // No-op; portal remains visible on failure.
105 }
106 }
107 Ok(())
108 }
109 })
110 .await?;
111
112 info!("WiFi connected");
113
114 // Convert the Button from WifiAuto into a ButtonWatch for background monitoring
115 let button_watch13 = ButtonWatch13::from_button(button, spawner)?;
116
117 // Read the timezone offset, an extra field that WiFi portal saved to flash.
118 let offset_minutes = timezone_field
119 .offset_minutes()?
120 .ok_or(Error::MissingCustomWifiAutoField)?;
121
122 // Create a ClockSync device that knows its timezone offset.
123 static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
124 let clock_sync = ClockSync::new(
125 &CLOCK_SYNC_STATIC,
126 stack,
127 offset_minutes,
128 Some(ONE_MINUTE),
129 spawner,
130 );
131
132 // Start in HH:MM mode
133 let mut state = State::HoursMinutes { speed: 1.0 };
134 loop {
135 state = match state {
136 State::HoursMinutes { speed } => {
137 state
138 .execute_hours_minutes(speed, &clock_sync, button_watch13, &servo_display)
139 .await?
140 }
141 State::MinutesSeconds => {
142 state
143 .execute_minutes_seconds(&clock_sync, button_watch13, &servo_display)
144 .await?
145 }
146 State::EditOffset => {
147 state
148 .execute_edit_offset(
149 &clock_sync,
150 button_watch13,
151 &timezone_field,
152 &servo_display,
153 )
154 .await?
155 }
156 };
157 }
158}84async fn inner_main(spawner: Spawner) -> Result<Infallible> {
85 info!("Starting Wi-Fi 8x12 LED clock (rotated display)");
86 let p = embassy_rp::init(Default::default());
87
88 // Use two blocks of flash storage: Wi-Fi credentials + timezone
89 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
90
91 // Define HTML to ask for timezone on the captive portal.
92 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
93 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
94
95 // Set up Wifi via a captive portal.
96 let wifi_auto = WifiAuto::new(
97 p.PIN_23, // CYW43 power
98 p.PIN_24, // CYW43 clock
99 p.PIN_25, // CYW43 chip select
100 p.PIN_29, // CYW43 data pin
101 p.PIO0, // CYW43 PIO interface
102 p.DMA_CH0, // CYW43 DMA channel
103 wifi_credentials_flash_block,
104 p.PIN_13, // Reset button pin (used only during WiFi setup)
105 PressedTo::Ground,
106 "www.picoclock.net", // Captive-portal SSID
107 [timezone_field], // Custom fields to ask for
108 spawner,
109 )?;
110
111 // Set up the 8x12 LED display on GPIO4.
112 let led8x12 = Led8x12::new(p.PIN_4, p.PIO1, p.DMA_CH1, spawner)?;
113
114 // Connect Wi-Fi, using the LED panel for status.
115 let led8x12_ref = &led8x12;
116 let (stack, button) = wifi_auto
117 .connect(|event| {
118 let led8x12_ref = led8x12_ref;
119 async move {
120 match event {
121 WifiAutoEvent::CaptivePortalReady => {
122 info!("WiFi: captive portal ready, displaying JOIN");
123 show_portal_ready(led8x12_ref).await?;
124 }
125 WifiAutoEvent::Connecting {
126 try_index,
127 try_count,
128 } => {
129 info!("WiFi: connecting (attempt {}/{})", try_index + 1, try_count);
130 show_connecting(led8x12_ref, try_index, try_count).await?;
131 }
132 WifiAutoEvent::ConnectionFailed => {
133 info!("WiFi: connection failed, displaying FAIL, device will reset");
134 show_connection_failed(led8x12_ref).await?;
135 }
136 }
137 Ok(())
138 }
139 })
140 .await?;
141
142 info!("WiFi: connected successfully, displaying DONE");
143 show_connected(&led8x12).await?;
144
145 // Convert the Button from WifiAuto into a ButtonWatch for background monitoring
146 let button_watch13 = ButtonWatch13::from_button(button, spawner)?;
147
148 // Read the timezone offset, an extra field that WiFi portal saved to flash.
149 let offset_minutes = timezone_field
150 .offset_minutes()?
151 .ok_or(Error::MissingCustomWifiAutoField)?;
152
153 // Create a clock synced over WiFi.
154 static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
155 let clock_sync = ClockSync::new(
156 &CLOCK_SYNC_STATIC,
157 stack,
158 offset_minutes,
159 Some(ONE_MINUTE),
160 spawner,
161 );
162
163 // Start in HH:MM mode
164 let mut state = State::HoursMinutes { speed: 1.0 };
165 loop {
166 state = match state {
167 State::HoursMinutes { speed } => {
168 state
169 .execute_hours_minutes(speed, &clock_sync, &button_watch13, &led8x12)
170 .await?
171 }
172 State::MinutesSeconds => {
173 state
174 .execute_minutes_seconds(&clock_sync, &button_watch13, &led8x12)
175 .await?
176 }
177 State::EditOffset => {
178 state
179 .execute_edit_offset(&clock_sync, &button_watch13, &timezone_field, &led8x12)
180 .await?
181 }
182 };
183 }
184}77async fn inner_main(spawner: Spawner) -> Result<Infallible> {
78 info!("Starting Wi-Fi 12x4 LED clock (WifiAuto)");
79 let p = embassy_rp::init(Default::default());
80
81 // Use two blocks of flash storage: Wi-Fi credentials + timezone
82 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
83
84 // Define HTML to ask for timezone on the captive portal.
85 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
86 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
87
88 // Set up Wifi via a captive portal. The button pin is used to reset stored credentials.
89 let wifi_auto = WifiAuto::new(
90 p.PIN_23, // CYW43 power
91 p.PIN_24, // CYW43 clock
92 p.PIN_25, // CYW43 chip select
93 p.PIN_29, // CYW43 data pin
94 p.PIO1, // CYW43 PIO interface (swapped to show PIO not hardcoded)
95 p.DMA_CH0, // CYW43 DMA channel
96 wifi_credentials_flash_block,
97 p.PIN_13, // Reset button pin
98 PressedTo::Ground,
99 "www.picoclock.net", // Captive-portal SSID
100 [timezone_field], // Custom fields to ask for
101 spawner,
102 )?;
103
104 // Set up the 12x4 LED display on GPIO3.
105 let led12x4 = Led12x4::new(p.PIN_3, p.PIO0, p.DMA_CH1, spawner)?;
106
107 // Connect Wi-Fi, using the LED panel for status.
108 let led12x4_ref = &led12x4;
109 let (stack, button) = wifi_auto
110 .connect(|event| {
111 let led12x4_ref = led12x4_ref;
112 async move {
113 match event {
114 WifiAutoEvent::CaptivePortalReady => {
115 info!("WiFi: captive portal ready, displaying JOIN");
116 show_portal_ready(led12x4_ref).await?;
117 }
118 WifiAutoEvent::Connecting {
119 try_index,
120 try_count,
121 } => {
122 info!("WiFi: connecting (attempt {}/{})", try_index + 1, try_count);
123 show_connecting(led12x4_ref, try_index, try_count).await?;
124 }
125 WifiAutoEvent::ConnectionFailed => {
126 info!("WiFi: connection failed, displaying FAIL, device will reset");
127 show_connection_failed(led12x4_ref).await?;
128 }
129 }
130 Ok(())
131 }
132 })
133 .await?;
134
135 info!("WiFi: connected successfully, displaying DONE");
136 show_connected(&led12x4).await?;
137
138 // Convert the Button from WifiAuto into a ButtonWatch for background monitoring
139 let button_watch13 = ButtonWatch13::from_button(button, spawner)?;
140
141 // Read the timezone offset, an extra field that WiFi portal saved to flash.
142 let offset_minutes = timezone_field
143 .offset_minutes()?
144 .ok_or(Error::MissingCustomWifiAutoField)?;
145
146 // Create a ClockSync device that knows its timezone offset.
147 static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
148 let clock_sync = ClockSync::new(
149 &CLOCK_SYNC_STATIC,
150 stack,
151 offset_minutes,
152 Some(ONE_MINUTE),
153 spawner,
154 );
155
156 // Start in HH:MM mode
157 let mut state = State::HoursMinutes { speed: 1.0 };
158 loop {
159 state = match state {
160 State::HoursMinutes { speed } => {
161 state
162 .execute_hours_minutes(speed, &clock_sync, button_watch13, &led12x4)
163 .await?
164 }
165 State::MinutesSeconds => {
166 state
167 .execute_minutes_seconds(&clock_sync, button_watch13, &led12x4)
168 .await?
169 }
170 State::EditOffset => {
171 state
172 .execute_edit_offset(&clock_sync, button_watch13, &timezone_field, &led12x4)
173 .await?
174 }
175 };
176 }
177}45async fn inner_main(spawner: Spawner) -> Result<Infallible> {
46 info!("Starting Wi-Fi 4-digit clock (WifiAuto)");
47 let p = embassy_rp::init(Default::default());
48
49 // Use two blocks of flash storage: Wi-Fi credentials + timezone
50 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
51
52 // Define HTML to ask for timezone on the captive portal.
53 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
54 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
55
56 // Set up Wifi via a captive portal. The button pin is used to reset stored credentials.
57 let wifi_auto = WifiAuto::new(
58 p.PIN_23, // CYW43 power
59 p.PIN_24, // CYW43 clock
60 p.PIN_25, // CYW43 chip select
61 p.PIN_29, // CYW43 data pin
62 p.PIO0, // CYW43 PIO interface
63 p.DMA_CH0, // CYW43 DMA channel
64 wifi_credentials_flash_block,
65 p.PIN_13, // Reset button pin
66 PressedTo::Ground,
67 "www.picoclock.net", // Captive-portal SSID
68 [timezone_field], // Custom fields to ask for
69 spawner,
70 )?;
71
72 // Set up the LED4 display.
73 let cell_pins = OutputArray::new([
74 gpio::Output::new(p.PIN_1, Level::High),
75 gpio::Output::new(p.PIN_2, Level::High),
76 gpio::Output::new(p.PIN_3, Level::High),
77 gpio::Output::new(p.PIN_4, Level::High),
78 ]);
79
80 let segment_pins = OutputArray::new([
81 gpio::Output::new(p.PIN_5, Level::Low),
82 gpio::Output::new(p.PIN_6, Level::Low),
83 gpio::Output::new(p.PIN_7, Level::Low),
84 gpio::Output::new(p.PIN_8, Level::Low),
85 gpio::Output::new(p.PIN_9, Level::Low),
86 gpio::Output::new(p.PIN_10, Level::Low),
87 gpio::Output::new(p.PIN_11, Level::Low),
88 gpio::Output::new(p.PIN_12, Level::Low),
89 ]);
90
91 static LED4_STATIC: Led4Static = Led4::new_static();
92 let led4 = Led4::new(&LED4_STATIC, cell_pins, segment_pins, spawner)?;
93
94 // Connect Wi-Fi, using the clock display for status.
95 let led4_ref = &led4;
96 let (stack, button) = wifi_auto
97 .connect(|event| async move {
98 match event {
99 WifiAutoEvent::CaptivePortalReady => {
100 led4_ref.write_text(['j', 'o', 'i', 'n'], BlinkState::BlinkingAndOn);
101 }
102 WifiAutoEvent::Connecting { .. } => {
103 led4_ref.animate_text(circular_outline_animation(true));
104 }
105 WifiAutoEvent::ConnectionFailed => {
106 led4_ref.write_text(['F', 'A', 'I', 'L'], BlinkState::BlinkingButOff);
107 }
108 }
109 Ok(())
110 })
111 .await?;
112
113 led4.write_text(['D', 'O', 'N', 'E'], BlinkState::Solid);
114 info!("WiFi connected");
115
116 // Convert the Button from WifiAuto into a ButtonWatch for background monitoring
117 let button_watch13 = ButtonWatch13::from_button(button, spawner)?;
118
119 // Read the timezone offset, an extra field that WiFi portal saved to flash.
120 let offset_minutes = timezone_field
121 .offset_minutes()?
122 .ok_or(Error::MissingCustomWifiAutoField)?;
123
124 // Create a ClockSync device that knows its timezone offset.
125 static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
126 let clock_sync = ClockSync::new(
127 &CLOCK_SYNC_STATIC,
128 stack,
129 offset_minutes,
130 Some(ONE_MINUTE),
131 spawner,
132 );
133
134 // Start in HH:MM mode
135 let mut state = State::HoursMinutes { speed: 1.0 };
136 loop {
137 state = match state {
138 State::HoursMinutes { speed } => {
139 state
140 .execute_hours_minutes(speed, &clock_sync, button_watch13, &led4)
141 .await?
142 }
143 State::MinutesSeconds => {
144 state
145 .execute_minutes_seconds(&clock_sync, button_watch13, &led4)
146 .await?
147 }
148 State::EditOffset => {
149 state
150 .execute_edit_offset(&clock_sync, button_watch13, &timezone_field, &led4)
151 .await?
152 }
153 };
154 }
155}Sourcepub async fn wait_for_tick(&self) -> ClockSyncTick
pub async fn wait_for_tick(&self) -> ClockSyncTick
Wait for and return the next tick after sync.
See the ClockSync struct example for usage.
Examples found in repository?
171 async fn execute_hours_minutes(
172 self,
173 speed: f32,
174 clock_sync: &ClockSync,
175 button_watch13: &ButtonWatch13,
176 servo_display: &ServoClockDisplay,
177 ) -> Result<Self> {
178 clock_sync.set_speed(speed).await;
179 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
180 servo_display.show_hours_minutes(hours, minutes).await;
181 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
182 loop {
183 match select(
184 button_watch13.wait_for_press_duration(),
185 clock_sync.wait_for_tick(),
186 )
187 .await
188 {
189 // Button pushes
190 Either::First(press_duration) => match (press_duration, speed.to_bits()) {
191 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
192 return Ok(Self::MinutesSeconds);
193 }
194 (PressDuration::Short, _) => {
195 return Ok(Self::HoursMinutes { speed: 1.0 });
196 }
197 (PressDuration::Long, _) => {
198 return Ok(Self::EditOffset);
199 }
200 },
201 // Clock tick
202 Either::Second(tick) => {
203 let (hours, minutes, _) = h12_m_s(&tick.local_time);
204 servo_display.show_hours_minutes(hours, minutes).await;
205 }
206 }
207 }
208 }
209
210 async fn execute_minutes_seconds(
211 self,
212 clock_sync: &ClockSync,
213 button_watch13: &ButtonWatch13,
214 servo_display: &ServoClockDisplay,
215 ) -> Result<Self> {
216 clock_sync.set_speed(1.0).await;
217 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
218 servo_display.show_minutes_seconds(minutes, seconds).await;
219 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
220 loop {
221 match select(
222 button_watch13.wait_for_press_duration(),
223 clock_sync.wait_for_tick(),
224 )
225 .await
226 {
227 // Button pushes
228 Either::First(PressDuration::Short) => {
229 return Ok(Self::HoursMinutes {
230 speed: FAST_MODE_SPEED,
231 });
232 }
233 Either::First(PressDuration::Long) => {
234 return Ok(Self::EditOffset);
235 }
236 // Clock tick
237 Either::Second(tick) => {
238 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
239 servo_display.show_minutes_seconds(minutes, seconds).await;
240 }
241 }
242 }
243 }More examples
197 async fn execute_hours_minutes(
198 self,
199 speed: f32,
200 clock_sync: &ClockSync,
201 button_watch13: &ButtonWatch13,
202 led8x12: &Led8x12,
203 ) -> Result<Self> {
204 clock_sync.set_speed(speed).await;
205 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
206 show_hours_minutes(led8x12, hours, minutes).await?;
207 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
208 loop {
209 match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
210 // Button pushes
211 Either::First(press_duration) => {
212 info!(
213 "HoursMinutes: Button press detected: {:?}, speed_bits={}",
214 press_duration,
215 speed.to_bits()
216 );
217 match (press_duration, speed.to_bits()) {
218 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
219 info!("HoursMinutes -> MinutesSeconds");
220 return Ok(Self::MinutesSeconds);
221 }
222 (PressDuration::Short, _) => {
223 info!("HoursMinutes: Resetting speed to 1.0");
224 return Ok(Self::HoursMinutes { speed: 1.0 });
225 }
226 (PressDuration::Long, _) => {
227 info!("HoursMinutes -> EditOffset");
228 return Ok(Self::EditOffset);
229 }
230 }
231 }
232 // Clock tick
233 Either::Second(tick_event) => {
234 let (hours, minutes, _) = h12_m_s(&tick_event.local_time);
235 show_hours_minutes(led8x12, hours, minutes).await?;
236 }
237 }
238 }
239 }
240
241 async fn execute_minutes_seconds(
242 self,
243 clock_sync: &ClockSync,
244 button_watch13: &ButtonWatch13,
245 led8x12: &Led8x12,
246 ) -> Result<Self> {
247 clock_sync.set_speed(1.0).await;
248 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
249 show_minutes_seconds(led8x12, minutes, seconds).await?;
250 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
251 loop {
252 match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
253 // Button pushes
254 Either::First(press_duration) => {
255 info!(
256 "MinutesSeconds: Button press detected: {:?}",
257 press_duration
258 );
259 match press_duration {
260 PressDuration::Short => {
261 info!("MinutesSeconds -> HoursMinutes (fast)");
262 return Ok(Self::HoursMinutes {
263 speed: FAST_MODE_SPEED,
264 });
265 }
266 PressDuration::Long => {
267 info!("MinutesSeconds -> EditOffset");
268 return Ok(Self::EditOffset);
269 }
270 }
271 }
272 // Clock tick
273 Either::Second(tick_event) => {
274 let (_, minutes, seconds) = h12_m_s(&tick_event.local_time);
275 show_minutes_seconds(led8x12, minutes, seconds).await?;
276 }
277 }
278 }
279 }190 async fn execute_hours_minutes(
191 self,
192 speed: f32,
193 clock_sync: &ClockSync,
194 button_watch13: &ButtonWatch13,
195 led12x4: &Led12x4,
196 ) -> Result<Self> {
197 clock_sync.set_speed(speed).await;
198 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
199 show_hours_minutes(led12x4, hours, minutes).await?;
200 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
201 loop {
202 match select(
203 button_watch13.wait_for_press_duration(),
204 clock_sync.wait_for_tick(),
205 )
206 .await
207 {
208 // Button pushes
209 Either::First(press_duration) => {
210 info!(
211 "HoursMinutes: Button press detected: {:?}, speed_bits={}",
212 press_duration,
213 speed.to_bits()
214 );
215 match (press_duration, speed.to_bits()) {
216 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
217 info!("HoursMinutes -> MinutesSeconds");
218 return Ok(Self::MinutesSeconds);
219 }
220 (PressDuration::Short, _) => {
221 info!("HoursMinutes: Resetting speed to 1.0");
222 return Ok(Self::HoursMinutes { speed: 1.0 });
223 }
224 (PressDuration::Long, _) => {
225 info!("HoursMinutes -> EditOffset");
226 return Ok(Self::EditOffset);
227 }
228 }
229 }
230 // Clock tick
231 Either::Second(tick) => {
232 let (hours, minutes, _) = h12_m_s(&tick.local_time);
233 show_hours_minutes(led12x4, hours, minutes).await?;
234 }
235 }
236 }
237 }
238
239 async fn execute_minutes_seconds(
240 self,
241 clock_sync: &ClockSync,
242 button_watch13: &ButtonWatch13,
243 led12x4: &Led12x4,
244 ) -> Result<Self> {
245 clock_sync.set_speed(1.0).await;
246 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
247 show_minutes_seconds(led12x4, minutes, seconds).await?;
248 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
249 loop {
250 match select(
251 button_watch13.wait_for_press_duration(),
252 clock_sync.wait_for_tick(),
253 )
254 .await
255 {
256 // Button pushes
257 Either::First(press_duration) => {
258 info!(
259 "MinutesSeconds: Button press detected: {:?}",
260 press_duration
261 );
262 match press_duration {
263 PressDuration::Short => {
264 info!("MinutesSeconds -> HoursMinutes (fast)");
265 return Ok(Self::HoursMinutes {
266 speed: FAST_MODE_SPEED,
267 });
268 }
269 PressDuration::Long => {
270 info!("MinutesSeconds -> EditOffset");
271 return Ok(Self::EditOffset);
272 }
273 }
274 }
275 // Clock tick
276 Either::Second(tick) => {
277 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
278 show_minutes_seconds(led12x4, minutes, seconds).await?;
279 }
280 }
281 }
282 }168 async fn execute_hours_minutes(
169 self,
170 speed: f32,
171 clock_sync: &ClockSync,
172 button_watch13: &ButtonWatch13,
173 led4: &Led4<'_>,
174 ) -> Result<Self> {
175 clock_sync.set_speed(speed).await;
176 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
177 led4.write_text(
178 [
179 Self::tens_hours(hours),
180 Self::ones_digit(hours),
181 Self::tens_digit(minutes),
182 Self::ones_digit(minutes),
183 ],
184 BlinkState::Solid,
185 );
186 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
187 loop {
188 match select(
189 button_watch13.wait_for_press_duration(),
190 clock_sync.wait_for_tick(),
191 )
192 .await
193 {
194 // Button pushes
195 Either::First(press_duration) => match (press_duration, speed.to_bits()) {
196 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
197 return Ok(Self::MinutesSeconds);
198 }
199 (PressDuration::Short, _) => {
200 return Ok(Self::HoursMinutes { speed: 1.0 });
201 }
202 (PressDuration::Long, _) => {
203 return Ok(Self::EditOffset);
204 }
205 },
206 // Clock tick
207 Either::Second(tick) => {
208 let (hours, minutes, _) = h12_m_s(&tick.local_time);
209 led4.write_text(
210 [
211 Self::tens_hours(hours),
212 Self::ones_digit(hours),
213 Self::tens_digit(minutes),
214 Self::ones_digit(minutes),
215 ],
216 BlinkState::Solid,
217 );
218 }
219 }
220 }
221 }
222
223 async fn execute_minutes_seconds(
224 self,
225 clock_sync: &ClockSync,
226 button_watch13: &ButtonWatch13,
227 led4: &Led4<'_>,
228 ) -> Result<Self> {
229 clock_sync.set_speed(1.0).await;
230 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
231 led4.write_text(
232 [
233 Self::tens_digit(minutes),
234 Self::ones_digit(minutes),
235 Self::tens_digit(seconds),
236 Self::ones_digit(seconds),
237 ],
238 BlinkState::Solid,
239 );
240 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
241 loop {
242 match select(
243 button_watch13.wait_for_press_duration(),
244 clock_sync.wait_for_tick(),
245 )
246 .await
247 {
248 // Button pushes
249 Either::First(PressDuration::Short) => {
250 return Ok(Self::HoursMinutes {
251 speed: FAST_MODE_SPEED,
252 });
253 }
254 Either::First(PressDuration::Long) => {
255 return Ok(Self::EditOffset);
256 }
257 // Clock tick
258 Either::Second(tick) => {
259 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
260 led4.write_text(
261 [
262 Self::tens_digit(minutes),
263 Self::ones_digit(minutes),
264 Self::tens_digit(seconds),
265 Self::ones_digit(seconds),
266 ],
267 BlinkState::Solid,
268 );
269 }
270 }
271 }
272 }32async fn inner_main(spawner: Spawner) -> Result<Infallible> {
33 info!("Starting Console Clock with WiFi");
34
35 // Initialize RP2040 peripherals
36 let p = embassy_rp::init(Default::default());
37
38 // Use two blocks of flash storage: Wi-Fi credentials + timezone
39 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
40
41 // Define timezone field for captive portal
42 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
43 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
44
45 // Set up WiFi via captive portal
46 let wifi_auto = WifiAuto::new(
47 p.PIN_23, // CYW43 power
48 p.PIN_24, // CYW43 clock
49 p.PIN_25, // CYW43 chip select
50 p.PIN_29, // CYW43 data pin
51 p.PIO0, // CYW43 PIO interface
52 p.DMA_CH0, // CYW43 DMA channel
53 wifi_credentials_flash_block,
54 p.PIN_13, // Reset button pin
55 PressedTo::Ground,
56 "www.picoclock.net",
57 [timezone_field],
58 spawner,
59 )?;
60
61 // Connect to WiFi
62 let (stack, _button) = wifi_auto
63 .connect(|event| async move {
64 match event {
65 WifiAutoEvent::CaptivePortalReady => {
66 info!("Captive portal ready - connect to WiFi network");
67 }
68 WifiAutoEvent::Connecting {
69 try_index,
70 try_count,
71 } => {
72 info!(
73 "Connecting to WiFi (attempt {} of {})...",
74 try_index + 1,
75 try_count
76 );
77 }
78 WifiAutoEvent::ConnectionFailed => {
79 info!("WiFi connection failed!");
80 }
81 }
82 Ok(())
83 })
84 .await?;
85
86 info!("WiFi connected successfully!");
87
88 // Create ClockSync device with timezone from WiFi portal
89 let timezone_offset_minutes = timezone_field
90 .offset_minutes()?
91 .ok_or(Error::MissingCustomWifiAutoField)?;
92 static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
93 let clock_sync = ClockSync::new(
94 &CLOCK_SYNC_STATIC,
95 stack,
96 timezone_offset_minutes,
97 Some(ONE_SECOND),
98 spawner,
99 );
100
101 info!("WiFi connected, entering event loop");
102
103 // Main event loop - log time on every tick
104 loop {
105 let tick = clock_sync.wait_for_tick().await;
106 let time_info = tick.local_time;
107 info!(
108 "Current time: {:04}-{:02}-{:02} {:02}:{:02}:{:02}",
109 time_info.year(),
110 u8::from(time_info.month()),
111 time_info.day(),
112 time_info.hour(),
113 time_info.minute(),
114 time_info.second(),
115 );
116 }
117}34async fn inner_main(spawner: Spawner) -> Result<Infallible> {
35 info!("Starting LCD Clock with WiFi");
36
37 // Initialize RP2040 peripherals
38 let p = embassy_rp::init(Default::default());
39
40 // Initialize CharLcd
41 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 // Use two blocks of flash storage: Wi-Fi credentials + timezone
45 let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
46
47 // Define timezone field for captive portal
48 static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
49 let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
50
51 // Set up WiFi via captive portal
52 let wifi_auto = WifiAuto::new(
53 p.PIN_23, // CYW43 power
54 p.PIN_24, // CYW43 clock
55 p.PIN_25, // CYW43 chip select
56 p.PIN_29, // CYW43 data pin
57 p.PIO0, // CYW43 PIO interface
58 p.DMA_CH0, // CYW43 DMA channel
59 wifi_credentials_flash_block,
60 p.PIN_13, // Reset button pin
61 PressedTo::Ground,
62 "www.picoclock.net",
63 [timezone_field],
64 spawner,
65 )?;
66
67 // Connect to WiFi
68 let (stack, _button) = wifi_auto.connect(|_event| async move { Ok(()) }).await?;
69
70 // Create ClockSync device with timezone from WiFi portal
71 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 // Main orchestrator loop - owns LCD and displays the clock
86 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}Sourcepub fn now_local(&self) -> OffsetDateTime
pub fn now_local(&self) -> OffsetDateTime
Get the current local time without waiting for a tick.
Examples found in repository?
171 async fn execute_hours_minutes(
172 self,
173 speed: f32,
174 clock_sync: &ClockSync,
175 button_watch13: &ButtonWatch13,
176 servo_display: &ServoClockDisplay,
177 ) -> Result<Self> {
178 clock_sync.set_speed(speed).await;
179 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
180 servo_display.show_hours_minutes(hours, minutes).await;
181 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
182 loop {
183 match select(
184 button_watch13.wait_for_press_duration(),
185 clock_sync.wait_for_tick(),
186 )
187 .await
188 {
189 // Button pushes
190 Either::First(press_duration) => match (press_duration, speed.to_bits()) {
191 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
192 return Ok(Self::MinutesSeconds);
193 }
194 (PressDuration::Short, _) => {
195 return Ok(Self::HoursMinutes { speed: 1.0 });
196 }
197 (PressDuration::Long, _) => {
198 return Ok(Self::EditOffset);
199 }
200 },
201 // Clock tick
202 Either::Second(tick) => {
203 let (hours, minutes, _) = h12_m_s(&tick.local_time);
204 servo_display.show_hours_minutes(hours, minutes).await;
205 }
206 }
207 }
208 }
209
210 async fn execute_minutes_seconds(
211 self,
212 clock_sync: &ClockSync,
213 button_watch13: &ButtonWatch13,
214 servo_display: &ServoClockDisplay,
215 ) -> Result<Self> {
216 clock_sync.set_speed(1.0).await;
217 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
218 servo_display.show_minutes_seconds(minutes, seconds).await;
219 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
220 loop {
221 match select(
222 button_watch13.wait_for_press_duration(),
223 clock_sync.wait_for_tick(),
224 )
225 .await
226 {
227 // Button pushes
228 Either::First(PressDuration::Short) => {
229 return Ok(Self::HoursMinutes {
230 speed: FAST_MODE_SPEED,
231 });
232 }
233 Either::First(PressDuration::Long) => {
234 return Ok(Self::EditOffset);
235 }
236 // Clock tick
237 Either::Second(tick) => {
238 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
239 servo_display.show_minutes_seconds(minutes, seconds).await;
240 }
241 }
242 }
243 }
244
245 async fn execute_edit_offset(
246 self,
247 clock_sync: &ClockSync,
248 button_watch13: &ButtonWatch13,
249 timezone_field: &TimezoneField,
250 servo_display: &ServoClockDisplay,
251 ) -> Result<Self> {
252 info!("Entering edit offset mode");
253 clock_sync.set_speed(1.0).await;
254
255 // Show current hours and minutes
256 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257 servo_display
258 .show_hours_minutes_indicator(hours, minutes)
259 .await;
260 // Add a gentle wiggle on the bottom servo to signal edit mode.
261 const WIGGLE: [(u16, Duration); 2] = [
262 (80, Duration::from_millis(250)),
263 (100, Duration::from_millis(250)),
264 ];
265 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267 // Get the current offset minutes from clock (source of truth)
268 let mut offset_minutes = clock_sync.offset_minutes();
269 info!("Current offset: {} minutes", offset_minutes);
270
271 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272 loop {
273 info!("Waiting for button press in edit mode");
274 match button_watch13.wait_for_press_duration().await {
275 PressDuration::Short => {
276 info!("Short press detected - incrementing offset");
277 // Increment the offset by 1 hour
278 offset_minutes += 60;
279 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280 if offset_minutes >= ONE_DAY_MINUTES {
281 offset_minutes -= ONE_DAY_MINUTES;
282 }
283 clock_sync.set_offset_minutes(offset_minutes).await;
284 info!("New offset: {} minutes", offset_minutes);
285
286 // Update display (atomic already updated, can use now_local)
287 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288 info!(
289 "Updated time after offset change: {:02}:{:02}",
290 hours, minutes
291 );
292 servo_display
293 .show_hours_minutes_indicator(hours, minutes)
294 .await;
295 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296 }
297 PressDuration::Long => {
298 info!("Long press detected - saving and exiting edit mode");
299 // Save to flash and exit edit mode
300 timezone_field.set_offset_minutes(offset_minutes)?;
301 info!("Offset saved to flash: {} minutes", offset_minutes);
302 return Ok(Self::HoursMinutes { speed: 1.0 });
303 }
304 }
305 }
306 }More examples
197 async fn execute_hours_minutes(
198 self,
199 speed: f32,
200 clock_sync: &ClockSync,
201 button_watch13: &ButtonWatch13,
202 led8x12: &Led8x12,
203 ) -> Result<Self> {
204 clock_sync.set_speed(speed).await;
205 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
206 show_hours_minutes(led8x12, hours, minutes).await?;
207 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
208 loop {
209 match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
210 // Button pushes
211 Either::First(press_duration) => {
212 info!(
213 "HoursMinutes: Button press detected: {:?}, speed_bits={}",
214 press_duration,
215 speed.to_bits()
216 );
217 match (press_duration, speed.to_bits()) {
218 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
219 info!("HoursMinutes -> MinutesSeconds");
220 return Ok(Self::MinutesSeconds);
221 }
222 (PressDuration::Short, _) => {
223 info!("HoursMinutes: Resetting speed to 1.0");
224 return Ok(Self::HoursMinutes { speed: 1.0 });
225 }
226 (PressDuration::Long, _) => {
227 info!("HoursMinutes -> EditOffset");
228 return Ok(Self::EditOffset);
229 }
230 }
231 }
232 // Clock tick
233 Either::Second(tick_event) => {
234 let (hours, minutes, _) = h12_m_s(&tick_event.local_time);
235 show_hours_minutes(led8x12, hours, minutes).await?;
236 }
237 }
238 }
239 }
240
241 async fn execute_minutes_seconds(
242 self,
243 clock_sync: &ClockSync,
244 button_watch13: &ButtonWatch13,
245 led8x12: &Led8x12,
246 ) -> Result<Self> {
247 clock_sync.set_speed(1.0).await;
248 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
249 show_minutes_seconds(led8x12, minutes, seconds).await?;
250 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
251 loop {
252 match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
253 // Button pushes
254 Either::First(press_duration) => {
255 info!(
256 "MinutesSeconds: Button press detected: {:?}",
257 press_duration
258 );
259 match press_duration {
260 PressDuration::Short => {
261 info!("MinutesSeconds -> HoursMinutes (fast)");
262 return Ok(Self::HoursMinutes {
263 speed: FAST_MODE_SPEED,
264 });
265 }
266 PressDuration::Long => {
267 info!("MinutesSeconds -> EditOffset");
268 return Ok(Self::EditOffset);
269 }
270 }
271 }
272 // Clock tick
273 Either::Second(tick_event) => {
274 let (_, minutes, seconds) = h12_m_s(&tick_event.local_time);
275 show_minutes_seconds(led8x12, minutes, seconds).await?;
276 }
277 }
278 }
279 }
280
281 async fn execute_edit_offset(
282 self,
283 clock_sync: &ClockSync,
284 button_watch13: &ButtonWatch13,
285 timezone_field: &TimezoneField,
286 led8x12: &Led8x12,
287 ) -> Result<Self> {
288 info!("Entering edit offset mode");
289 clock_sync.set_speed(1.0).await;
290
291 // Blink current hours and minutes with edit color accent.
292 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 loop {
301 info!("Waiting for button press in edit mode");
302 match button_watch13.wait_for_press_duration().await {
303 PressDuration::Short => {
304 info!("Short press detected - incrementing offset");
305 // Increment the offset by 1 hour
306 offset_minutes += 60;
307 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308 if offset_minutes >= ONE_DAY_MINUTES {
309 offset_minutes -= ONE_DAY_MINUTES;
310 }
311 clock_sync.set_offset_minutes(offset_minutes).await;
312 info!("New offset: {} minutes", offset_minutes);
313
314 // Update display
315 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316 info!(
317 "Updated time after offset change: {:02}:{:02}",
318 hours, minutes
319 );
320 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321 }
322 PressDuration::Long => {
323 info!("Long press detected - saving and exiting edit mode");
324 // Save to flash and exit edit mode
325 timezone_field.set_offset_minutes(offset_minutes)?;
326 info!("Offset saved to flash: {} minutes", offset_minutes);
327 return Ok(Self::HoursMinutes { speed: 1.0 });
328 }
329 }
330 }
331 }190 async fn execute_hours_minutes(
191 self,
192 speed: f32,
193 clock_sync: &ClockSync,
194 button_watch13: &ButtonWatch13,
195 led12x4: &Led12x4,
196 ) -> Result<Self> {
197 clock_sync.set_speed(speed).await;
198 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
199 show_hours_minutes(led12x4, hours, minutes).await?;
200 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
201 loop {
202 match select(
203 button_watch13.wait_for_press_duration(),
204 clock_sync.wait_for_tick(),
205 )
206 .await
207 {
208 // Button pushes
209 Either::First(press_duration) => {
210 info!(
211 "HoursMinutes: Button press detected: {:?}, speed_bits={}",
212 press_duration,
213 speed.to_bits()
214 );
215 match (press_duration, speed.to_bits()) {
216 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
217 info!("HoursMinutes -> MinutesSeconds");
218 return Ok(Self::MinutesSeconds);
219 }
220 (PressDuration::Short, _) => {
221 info!("HoursMinutes: Resetting speed to 1.0");
222 return Ok(Self::HoursMinutes { speed: 1.0 });
223 }
224 (PressDuration::Long, _) => {
225 info!("HoursMinutes -> EditOffset");
226 return Ok(Self::EditOffset);
227 }
228 }
229 }
230 // Clock tick
231 Either::Second(tick) => {
232 let (hours, minutes, _) = h12_m_s(&tick.local_time);
233 show_hours_minutes(led12x4, hours, minutes).await?;
234 }
235 }
236 }
237 }
238
239 async fn execute_minutes_seconds(
240 self,
241 clock_sync: &ClockSync,
242 button_watch13: &ButtonWatch13,
243 led12x4: &Led12x4,
244 ) -> Result<Self> {
245 clock_sync.set_speed(1.0).await;
246 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
247 show_minutes_seconds(led12x4, minutes, seconds).await?;
248 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
249 loop {
250 match select(
251 button_watch13.wait_for_press_duration(),
252 clock_sync.wait_for_tick(),
253 )
254 .await
255 {
256 // Button pushes
257 Either::First(press_duration) => {
258 info!(
259 "MinutesSeconds: Button press detected: {:?}",
260 press_duration
261 );
262 match press_duration {
263 PressDuration::Short => {
264 info!("MinutesSeconds -> HoursMinutes (fast)");
265 return Ok(Self::HoursMinutes {
266 speed: FAST_MODE_SPEED,
267 });
268 }
269 PressDuration::Long => {
270 info!("MinutesSeconds -> EditOffset");
271 return Ok(Self::EditOffset);
272 }
273 }
274 }
275 // Clock tick
276 Either::Second(tick) => {
277 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
278 show_minutes_seconds(led12x4, minutes, seconds).await?;
279 }
280 }
281 }
282 }
283
284 async fn execute_edit_offset(
285 self,
286 clock_sync: &ClockSync,
287 button_watch13: &ButtonWatch13,
288 timezone_field: &TimezoneField,
289 led12x4: &Led12x4,
290 ) -> Result<Self> {
291 info!("Entering edit offset mode");
292 clock_sync.set_speed(1.0).await;
293
294 // Blink current hours and minutes with edit color accent.
295 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298 // Get the current offset minutes from clock (source of truth)
299 let mut offset_minutes = clock_sync.offset_minutes();
300 info!("Current offset: {} minutes", offset_minutes);
301
302 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303 loop {
304 info!("Waiting for button press in edit mode");
305 match button_watch13.wait_for_press_duration().await {
306 PressDuration::Short => {
307 info!("Short press detected - incrementing offset");
308 // Increment the offset by 1 hour
309 offset_minutes += 60;
310 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311 if offset_minutes >= ONE_DAY_MINUTES {
312 offset_minutes -= ONE_DAY_MINUTES;
313 }
314 clock_sync.set_offset_minutes(offset_minutes).await;
315 info!("New offset: {} minutes", offset_minutes);
316
317 // Update display (atomic already updated, can use now_local)
318 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319 info!(
320 "Updated time after offset change: {:02}:{:02}",
321 hours, minutes
322 );
323 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324 }
325 PressDuration::Long => {
326 info!("Long press detected - saving and exiting edit mode");
327 // Save to flash and exit edit mode
328 timezone_field.set_offset_minutes(offset_minutes)?;
329 info!("Offset saved to flash: {} minutes", offset_minutes);
330 return Ok(Self::HoursMinutes { speed: 1.0 });
331 }
332 }
333 }
334 }168 async fn execute_hours_minutes(
169 self,
170 speed: f32,
171 clock_sync: &ClockSync,
172 button_watch13: &ButtonWatch13,
173 led4: &Led4<'_>,
174 ) -> Result<Self> {
175 clock_sync.set_speed(speed).await;
176 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
177 led4.write_text(
178 [
179 Self::tens_hours(hours),
180 Self::ones_digit(hours),
181 Self::tens_digit(minutes),
182 Self::ones_digit(minutes),
183 ],
184 BlinkState::Solid,
185 );
186 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
187 loop {
188 match select(
189 button_watch13.wait_for_press_duration(),
190 clock_sync.wait_for_tick(),
191 )
192 .await
193 {
194 // Button pushes
195 Either::First(press_duration) => match (press_duration, speed.to_bits()) {
196 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
197 return Ok(Self::MinutesSeconds);
198 }
199 (PressDuration::Short, _) => {
200 return Ok(Self::HoursMinutes { speed: 1.0 });
201 }
202 (PressDuration::Long, _) => {
203 return Ok(Self::EditOffset);
204 }
205 },
206 // Clock tick
207 Either::Second(tick) => {
208 let (hours, minutes, _) = h12_m_s(&tick.local_time);
209 led4.write_text(
210 [
211 Self::tens_hours(hours),
212 Self::ones_digit(hours),
213 Self::tens_digit(minutes),
214 Self::ones_digit(minutes),
215 ],
216 BlinkState::Solid,
217 );
218 }
219 }
220 }
221 }
222
223 async fn execute_minutes_seconds(
224 self,
225 clock_sync: &ClockSync,
226 button_watch13: &ButtonWatch13,
227 led4: &Led4<'_>,
228 ) -> Result<Self> {
229 clock_sync.set_speed(1.0).await;
230 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
231 led4.write_text(
232 [
233 Self::tens_digit(minutes),
234 Self::ones_digit(minutes),
235 Self::tens_digit(seconds),
236 Self::ones_digit(seconds),
237 ],
238 BlinkState::Solid,
239 );
240 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
241 loop {
242 match select(
243 button_watch13.wait_for_press_duration(),
244 clock_sync.wait_for_tick(),
245 )
246 .await
247 {
248 // Button pushes
249 Either::First(PressDuration::Short) => {
250 return Ok(Self::HoursMinutes {
251 speed: FAST_MODE_SPEED,
252 });
253 }
254 Either::First(PressDuration::Long) => {
255 return Ok(Self::EditOffset);
256 }
257 // Clock tick
258 Either::Second(tick) => {
259 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
260 led4.write_text(
261 [
262 Self::tens_digit(minutes),
263 Self::ones_digit(minutes),
264 Self::tens_digit(seconds),
265 Self::ones_digit(seconds),
266 ],
267 BlinkState::Solid,
268 );
269 }
270 }
271 }
272 }
273
274 async fn execute_edit_offset(
275 self,
276 clock_sync: &ClockSync,
277 button_watch13: &ButtonWatch13,
278 timezone_field: &TimezoneField,
279 led4: &Led4<'_>,
280 ) -> Result<Self> {
281 info!("Entering edit offset mode");
282
283 // Blink current hours and minutes
284 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285 led4.write_text(
286 [
287 Self::tens_hours(hours),
288 Self::ones_digit(hours),
289 Self::tens_digit(minutes),
290 Self::ones_digit(minutes),
291 ],
292 BlinkState::BlinkingAndOn,
293 );
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 clock_sync.set_speed(1.0).await;
301 loop {
302 info!("Waiting for button press in edit mode");
303 match button_watch13.wait_for_press_duration().await {
304 PressDuration::Short => {
305 info!("Short press detected - incrementing offset");
306 // Increment the offset by 1 hour
307 offset_minutes += 60;
308 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309 if offset_minutes >= ONE_DAY_MINUTES {
310 offset_minutes -= ONE_DAY_MINUTES;
311 }
312 clock_sync.set_offset_minutes(offset_minutes).await;
313 info!("New offset: {} minutes", offset_minutes);
314
315 // Update display (atomic already updated, can use now_local)
316 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317 info!(
318 "Updated time after offset change: {:02}:{:02}",
319 hours, minutes
320 );
321 led4.write_text(
322 [
323 Self::tens_hours(hours),
324 Self::ones_digit(hours),
325 Self::tens_digit(minutes),
326 Self::ones_digit(minutes),
327 ],
328 BlinkState::BlinkingAndOn,
329 );
330 }
331 PressDuration::Long => {
332 info!("Long press detected - saving and exiting edit mode");
333 // Save to flash and exit edit mode
334 timezone_field.set_offset_minutes(offset_minutes)?;
335 info!("Offset saved to flash: {} minutes", offset_minutes);
336 return Ok(Self::HoursMinutes { speed: 1.0 });
337 }
338 }
339 }
340 }Sourcepub async fn set_offset_minutes(&self, minutes: i32)
pub async fn set_offset_minutes(&self, minutes: i32)
Update the UTC offset used for local time.
Examples found in repository?
281 async fn execute_edit_offset(
282 self,
283 clock_sync: &ClockSync,
284 button_watch13: &ButtonWatch13,
285 timezone_field: &TimezoneField,
286 led8x12: &Led8x12,
287 ) -> Result<Self> {
288 info!("Entering edit offset mode");
289 clock_sync.set_speed(1.0).await;
290
291 // Blink current hours and minutes with edit color accent.
292 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 loop {
301 info!("Waiting for button press in edit mode");
302 match button_watch13.wait_for_press_duration().await {
303 PressDuration::Short => {
304 info!("Short press detected - incrementing offset");
305 // Increment the offset by 1 hour
306 offset_minutes += 60;
307 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308 if offset_minutes >= ONE_DAY_MINUTES {
309 offset_minutes -= ONE_DAY_MINUTES;
310 }
311 clock_sync.set_offset_minutes(offset_minutes).await;
312 info!("New offset: {} minutes", offset_minutes);
313
314 // Update display
315 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316 info!(
317 "Updated time after offset change: {:02}:{:02}",
318 hours, minutes
319 );
320 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321 }
322 PressDuration::Long => {
323 info!("Long press detected - saving and exiting edit mode");
324 // Save to flash and exit edit mode
325 timezone_field.set_offset_minutes(offset_minutes)?;
326 info!("Offset saved to flash: {} minutes", offset_minutes);
327 return Ok(Self::HoursMinutes { speed: 1.0 });
328 }
329 }
330 }
331 }More examples
284 async fn execute_edit_offset(
285 self,
286 clock_sync: &ClockSync,
287 button_watch13: &ButtonWatch13,
288 timezone_field: &TimezoneField,
289 led12x4: &Led12x4,
290 ) -> Result<Self> {
291 info!("Entering edit offset mode");
292 clock_sync.set_speed(1.0).await;
293
294 // Blink current hours and minutes with edit color accent.
295 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298 // Get the current offset minutes from clock (source of truth)
299 let mut offset_minutes = clock_sync.offset_minutes();
300 info!("Current offset: {} minutes", offset_minutes);
301
302 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303 loop {
304 info!("Waiting for button press in edit mode");
305 match button_watch13.wait_for_press_duration().await {
306 PressDuration::Short => {
307 info!("Short press detected - incrementing offset");
308 // Increment the offset by 1 hour
309 offset_minutes += 60;
310 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311 if offset_minutes >= ONE_DAY_MINUTES {
312 offset_minutes -= ONE_DAY_MINUTES;
313 }
314 clock_sync.set_offset_minutes(offset_minutes).await;
315 info!("New offset: {} minutes", offset_minutes);
316
317 // Update display (atomic already updated, can use now_local)
318 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319 info!(
320 "Updated time after offset change: {:02}:{:02}",
321 hours, minutes
322 );
323 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324 }
325 PressDuration::Long => {
326 info!("Long press detected - saving and exiting edit mode");
327 // Save to flash and exit edit mode
328 timezone_field.set_offset_minutes(offset_minutes)?;
329 info!("Offset saved to flash: {} minutes", offset_minutes);
330 return Ok(Self::HoursMinutes { speed: 1.0 });
331 }
332 }
333 }
334 }245 async fn execute_edit_offset(
246 self,
247 clock_sync: &ClockSync,
248 button_watch13: &ButtonWatch13,
249 timezone_field: &TimezoneField,
250 servo_display: &ServoClockDisplay,
251 ) -> Result<Self> {
252 info!("Entering edit offset mode");
253 clock_sync.set_speed(1.0).await;
254
255 // Show current hours and minutes
256 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257 servo_display
258 .show_hours_minutes_indicator(hours, minutes)
259 .await;
260 // Add a gentle wiggle on the bottom servo to signal edit mode.
261 const WIGGLE: [(u16, Duration); 2] = [
262 (80, Duration::from_millis(250)),
263 (100, Duration::from_millis(250)),
264 ];
265 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267 // Get the current offset minutes from clock (source of truth)
268 let mut offset_minutes = clock_sync.offset_minutes();
269 info!("Current offset: {} minutes", offset_minutes);
270
271 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272 loop {
273 info!("Waiting for button press in edit mode");
274 match button_watch13.wait_for_press_duration().await {
275 PressDuration::Short => {
276 info!("Short press detected - incrementing offset");
277 // Increment the offset by 1 hour
278 offset_minutes += 60;
279 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280 if offset_minutes >= ONE_DAY_MINUTES {
281 offset_minutes -= ONE_DAY_MINUTES;
282 }
283 clock_sync.set_offset_minutes(offset_minutes).await;
284 info!("New offset: {} minutes", offset_minutes);
285
286 // Update display (atomic already updated, can use now_local)
287 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288 info!(
289 "Updated time after offset change: {:02}:{:02}",
290 hours, minutes
291 );
292 servo_display
293 .show_hours_minutes_indicator(hours, minutes)
294 .await;
295 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296 }
297 PressDuration::Long => {
298 info!("Long press detected - saving and exiting edit mode");
299 // Save to flash and exit edit mode
300 timezone_field.set_offset_minutes(offset_minutes)?;
301 info!("Offset saved to flash: {} minutes", offset_minutes);
302 return Ok(Self::HoursMinutes { speed: 1.0 });
303 }
304 }
305 }
306 }274 async fn execute_edit_offset(
275 self,
276 clock_sync: &ClockSync,
277 button_watch13: &ButtonWatch13,
278 timezone_field: &TimezoneField,
279 led4: &Led4<'_>,
280 ) -> Result<Self> {
281 info!("Entering edit offset mode");
282
283 // Blink current hours and minutes
284 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285 led4.write_text(
286 [
287 Self::tens_hours(hours),
288 Self::ones_digit(hours),
289 Self::tens_digit(minutes),
290 Self::ones_digit(minutes),
291 ],
292 BlinkState::BlinkingAndOn,
293 );
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 clock_sync.set_speed(1.0).await;
301 loop {
302 info!("Waiting for button press in edit mode");
303 match button_watch13.wait_for_press_duration().await {
304 PressDuration::Short => {
305 info!("Short press detected - incrementing offset");
306 // Increment the offset by 1 hour
307 offset_minutes += 60;
308 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309 if offset_minutes >= ONE_DAY_MINUTES {
310 offset_minutes -= ONE_DAY_MINUTES;
311 }
312 clock_sync.set_offset_minutes(offset_minutes).await;
313 info!("New offset: {} minutes", offset_minutes);
314
315 // Update display (atomic already updated, can use now_local)
316 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317 info!(
318 "Updated time after offset change: {:02}:{:02}",
319 hours, minutes
320 );
321 led4.write_text(
322 [
323 Self::tens_hours(hours),
324 Self::ones_digit(hours),
325 Self::tens_digit(minutes),
326 Self::ones_digit(minutes),
327 ],
328 BlinkState::BlinkingAndOn,
329 );
330 }
331 PressDuration::Long => {
332 info!("Long press detected - saving and exiting edit mode");
333 // Save to flash and exit edit mode
334 timezone_field.set_offset_minutes(offset_minutes)?;
335 info!("Offset saved to flash: {} minutes", offset_minutes);
336 return Ok(Self::HoursMinutes { speed: 1.0 });
337 }
338 }
339 }
340 }Sourcepub fn offset_minutes(&self) -> i32
pub fn offset_minutes(&self) -> i32
Get the current UTC offset in minutes.
Examples found in repository?
281 async fn execute_edit_offset(
282 self,
283 clock_sync: &ClockSync,
284 button_watch13: &ButtonWatch13,
285 timezone_field: &TimezoneField,
286 led8x12: &Led8x12,
287 ) -> Result<Self> {
288 info!("Entering edit offset mode");
289 clock_sync.set_speed(1.0).await;
290
291 // Blink current hours and minutes with edit color accent.
292 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 loop {
301 info!("Waiting for button press in edit mode");
302 match button_watch13.wait_for_press_duration().await {
303 PressDuration::Short => {
304 info!("Short press detected - incrementing offset");
305 // Increment the offset by 1 hour
306 offset_minutes += 60;
307 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308 if offset_minutes >= ONE_DAY_MINUTES {
309 offset_minutes -= ONE_DAY_MINUTES;
310 }
311 clock_sync.set_offset_minutes(offset_minutes).await;
312 info!("New offset: {} minutes", offset_minutes);
313
314 // Update display
315 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316 info!(
317 "Updated time after offset change: {:02}:{:02}",
318 hours, minutes
319 );
320 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321 }
322 PressDuration::Long => {
323 info!("Long press detected - saving and exiting edit mode");
324 // Save to flash and exit edit mode
325 timezone_field.set_offset_minutes(offset_minutes)?;
326 info!("Offset saved to flash: {} minutes", offset_minutes);
327 return Ok(Self::HoursMinutes { speed: 1.0 });
328 }
329 }
330 }
331 }More examples
284 async fn execute_edit_offset(
285 self,
286 clock_sync: &ClockSync,
287 button_watch13: &ButtonWatch13,
288 timezone_field: &TimezoneField,
289 led12x4: &Led12x4,
290 ) -> Result<Self> {
291 info!("Entering edit offset mode");
292 clock_sync.set_speed(1.0).await;
293
294 // Blink current hours and minutes with edit color accent.
295 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298 // Get the current offset minutes from clock (source of truth)
299 let mut offset_minutes = clock_sync.offset_minutes();
300 info!("Current offset: {} minutes", offset_minutes);
301
302 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303 loop {
304 info!("Waiting for button press in edit mode");
305 match button_watch13.wait_for_press_duration().await {
306 PressDuration::Short => {
307 info!("Short press detected - incrementing offset");
308 // Increment the offset by 1 hour
309 offset_minutes += 60;
310 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311 if offset_minutes >= ONE_DAY_MINUTES {
312 offset_minutes -= ONE_DAY_MINUTES;
313 }
314 clock_sync.set_offset_minutes(offset_minutes).await;
315 info!("New offset: {} minutes", offset_minutes);
316
317 // Update display (atomic already updated, can use now_local)
318 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319 info!(
320 "Updated time after offset change: {:02}:{:02}",
321 hours, minutes
322 );
323 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324 }
325 PressDuration::Long => {
326 info!("Long press detected - saving and exiting edit mode");
327 // Save to flash and exit edit mode
328 timezone_field.set_offset_minutes(offset_minutes)?;
329 info!("Offset saved to flash: {} minutes", offset_minutes);
330 return Ok(Self::HoursMinutes { speed: 1.0 });
331 }
332 }
333 }
334 }245 async fn execute_edit_offset(
246 self,
247 clock_sync: &ClockSync,
248 button_watch13: &ButtonWatch13,
249 timezone_field: &TimezoneField,
250 servo_display: &ServoClockDisplay,
251 ) -> Result<Self> {
252 info!("Entering edit offset mode");
253 clock_sync.set_speed(1.0).await;
254
255 // Show current hours and minutes
256 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257 servo_display
258 .show_hours_minutes_indicator(hours, minutes)
259 .await;
260 // Add a gentle wiggle on the bottom servo to signal edit mode.
261 const WIGGLE: [(u16, Duration); 2] = [
262 (80, Duration::from_millis(250)),
263 (100, Duration::from_millis(250)),
264 ];
265 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267 // Get the current offset minutes from clock (source of truth)
268 let mut offset_minutes = clock_sync.offset_minutes();
269 info!("Current offset: {} minutes", offset_minutes);
270
271 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272 loop {
273 info!("Waiting for button press in edit mode");
274 match button_watch13.wait_for_press_duration().await {
275 PressDuration::Short => {
276 info!("Short press detected - incrementing offset");
277 // Increment the offset by 1 hour
278 offset_minutes += 60;
279 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280 if offset_minutes >= ONE_DAY_MINUTES {
281 offset_minutes -= ONE_DAY_MINUTES;
282 }
283 clock_sync.set_offset_minutes(offset_minutes).await;
284 info!("New offset: {} minutes", offset_minutes);
285
286 // Update display (atomic already updated, can use now_local)
287 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288 info!(
289 "Updated time after offset change: {:02}:{:02}",
290 hours, minutes
291 );
292 servo_display
293 .show_hours_minutes_indicator(hours, minutes)
294 .await;
295 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296 }
297 PressDuration::Long => {
298 info!("Long press detected - saving and exiting edit mode");
299 // Save to flash and exit edit mode
300 timezone_field.set_offset_minutes(offset_minutes)?;
301 info!("Offset saved to flash: {} minutes", offset_minutes);
302 return Ok(Self::HoursMinutes { speed: 1.0 });
303 }
304 }
305 }
306 }274 async fn execute_edit_offset(
275 self,
276 clock_sync: &ClockSync,
277 button_watch13: &ButtonWatch13,
278 timezone_field: &TimezoneField,
279 led4: &Led4<'_>,
280 ) -> Result<Self> {
281 info!("Entering edit offset mode");
282
283 // Blink current hours and minutes
284 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285 led4.write_text(
286 [
287 Self::tens_hours(hours),
288 Self::ones_digit(hours),
289 Self::tens_digit(minutes),
290 Self::ones_digit(minutes),
291 ],
292 BlinkState::BlinkingAndOn,
293 );
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 clock_sync.set_speed(1.0).await;
301 loop {
302 info!("Waiting for button press in edit mode");
303 match button_watch13.wait_for_press_duration().await {
304 PressDuration::Short => {
305 info!("Short press detected - incrementing offset");
306 // Increment the offset by 1 hour
307 offset_minutes += 60;
308 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309 if offset_minutes >= ONE_DAY_MINUTES {
310 offset_minutes -= ONE_DAY_MINUTES;
311 }
312 clock_sync.set_offset_minutes(offset_minutes).await;
313 info!("New offset: {} minutes", offset_minutes);
314
315 // Update display (atomic already updated, can use now_local)
316 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317 info!(
318 "Updated time after offset change: {:02}:{:02}",
319 hours, minutes
320 );
321 led4.write_text(
322 [
323 Self::tens_hours(hours),
324 Self::ones_digit(hours),
325 Self::tens_digit(minutes),
326 Self::ones_digit(minutes),
327 ],
328 BlinkState::BlinkingAndOn,
329 );
330 }
331 PressDuration::Long => {
332 info!("Long press detected - saving and exiting edit mode");
333 // Save to flash and exit edit mode
334 timezone_field.set_offset_minutes(offset_minutes)?;
335 info!("Offset saved to flash: {} minutes", offset_minutes);
336 return Ok(Self::HoursMinutes { speed: 1.0 });
337 }
338 }
339 }
340 }Sourcepub async fn set_tick_interval(&self, interval: Option<Duration>)
pub async fn set_tick_interval(&self, interval: Option<Duration>)
Set the tick interval. Use None to disable periodic ticks.
Examples found in repository?
171 async fn execute_hours_minutes(
172 self,
173 speed: f32,
174 clock_sync: &ClockSync,
175 button_watch13: &ButtonWatch13,
176 servo_display: &ServoClockDisplay,
177 ) -> Result<Self> {
178 clock_sync.set_speed(speed).await;
179 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
180 servo_display.show_hours_minutes(hours, minutes).await;
181 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
182 loop {
183 match select(
184 button_watch13.wait_for_press_duration(),
185 clock_sync.wait_for_tick(),
186 )
187 .await
188 {
189 // Button pushes
190 Either::First(press_duration) => match (press_duration, speed.to_bits()) {
191 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
192 return Ok(Self::MinutesSeconds);
193 }
194 (PressDuration::Short, _) => {
195 return Ok(Self::HoursMinutes { speed: 1.0 });
196 }
197 (PressDuration::Long, _) => {
198 return Ok(Self::EditOffset);
199 }
200 },
201 // Clock tick
202 Either::Second(tick) => {
203 let (hours, minutes, _) = h12_m_s(&tick.local_time);
204 servo_display.show_hours_minutes(hours, minutes).await;
205 }
206 }
207 }
208 }
209
210 async fn execute_minutes_seconds(
211 self,
212 clock_sync: &ClockSync,
213 button_watch13: &ButtonWatch13,
214 servo_display: &ServoClockDisplay,
215 ) -> Result<Self> {
216 clock_sync.set_speed(1.0).await;
217 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
218 servo_display.show_minutes_seconds(minutes, seconds).await;
219 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
220 loop {
221 match select(
222 button_watch13.wait_for_press_duration(),
223 clock_sync.wait_for_tick(),
224 )
225 .await
226 {
227 // Button pushes
228 Either::First(PressDuration::Short) => {
229 return Ok(Self::HoursMinutes {
230 speed: FAST_MODE_SPEED,
231 });
232 }
233 Either::First(PressDuration::Long) => {
234 return Ok(Self::EditOffset);
235 }
236 // Clock tick
237 Either::Second(tick) => {
238 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
239 servo_display.show_minutes_seconds(minutes, seconds).await;
240 }
241 }
242 }
243 }
244
245 async fn execute_edit_offset(
246 self,
247 clock_sync: &ClockSync,
248 button_watch13: &ButtonWatch13,
249 timezone_field: &TimezoneField,
250 servo_display: &ServoClockDisplay,
251 ) -> Result<Self> {
252 info!("Entering edit offset mode");
253 clock_sync.set_speed(1.0).await;
254
255 // Show current hours and minutes
256 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257 servo_display
258 .show_hours_minutes_indicator(hours, minutes)
259 .await;
260 // Add a gentle wiggle on the bottom servo to signal edit mode.
261 const WIGGLE: [(u16, Duration); 2] = [
262 (80, Duration::from_millis(250)),
263 (100, Duration::from_millis(250)),
264 ];
265 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267 // Get the current offset minutes from clock (source of truth)
268 let mut offset_minutes = clock_sync.offset_minutes();
269 info!("Current offset: {} minutes", offset_minutes);
270
271 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272 loop {
273 info!("Waiting for button press in edit mode");
274 match button_watch13.wait_for_press_duration().await {
275 PressDuration::Short => {
276 info!("Short press detected - incrementing offset");
277 // Increment the offset by 1 hour
278 offset_minutes += 60;
279 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280 if offset_minutes >= ONE_DAY_MINUTES {
281 offset_minutes -= ONE_DAY_MINUTES;
282 }
283 clock_sync.set_offset_minutes(offset_minutes).await;
284 info!("New offset: {} minutes", offset_minutes);
285
286 // Update display (atomic already updated, can use now_local)
287 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288 info!(
289 "Updated time after offset change: {:02}:{:02}",
290 hours, minutes
291 );
292 servo_display
293 .show_hours_minutes_indicator(hours, minutes)
294 .await;
295 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296 }
297 PressDuration::Long => {
298 info!("Long press detected - saving and exiting edit mode");
299 // Save to flash and exit edit mode
300 timezone_field.set_offset_minutes(offset_minutes)?;
301 info!("Offset saved to flash: {} minutes", offset_minutes);
302 return Ok(Self::HoursMinutes { speed: 1.0 });
303 }
304 }
305 }
306 }More examples
197 async fn execute_hours_minutes(
198 self,
199 speed: f32,
200 clock_sync: &ClockSync,
201 button_watch13: &ButtonWatch13,
202 led8x12: &Led8x12,
203 ) -> Result<Self> {
204 clock_sync.set_speed(speed).await;
205 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
206 show_hours_minutes(led8x12, hours, minutes).await?;
207 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
208 loop {
209 match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
210 // Button pushes
211 Either::First(press_duration) => {
212 info!(
213 "HoursMinutes: Button press detected: {:?}, speed_bits={}",
214 press_duration,
215 speed.to_bits()
216 );
217 match (press_duration, speed.to_bits()) {
218 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
219 info!("HoursMinutes -> MinutesSeconds");
220 return Ok(Self::MinutesSeconds);
221 }
222 (PressDuration::Short, _) => {
223 info!("HoursMinutes: Resetting speed to 1.0");
224 return Ok(Self::HoursMinutes { speed: 1.0 });
225 }
226 (PressDuration::Long, _) => {
227 info!("HoursMinutes -> EditOffset");
228 return Ok(Self::EditOffset);
229 }
230 }
231 }
232 // Clock tick
233 Either::Second(tick_event) => {
234 let (hours, minutes, _) = h12_m_s(&tick_event.local_time);
235 show_hours_minutes(led8x12, hours, minutes).await?;
236 }
237 }
238 }
239 }
240
241 async fn execute_minutes_seconds(
242 self,
243 clock_sync: &ClockSync,
244 button_watch13: &ButtonWatch13,
245 led8x12: &Led8x12,
246 ) -> Result<Self> {
247 clock_sync.set_speed(1.0).await;
248 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
249 show_minutes_seconds(led8x12, minutes, seconds).await?;
250 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
251 loop {
252 match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
253 // Button pushes
254 Either::First(press_duration) => {
255 info!(
256 "MinutesSeconds: Button press detected: {:?}",
257 press_duration
258 );
259 match press_duration {
260 PressDuration::Short => {
261 info!("MinutesSeconds -> HoursMinutes (fast)");
262 return Ok(Self::HoursMinutes {
263 speed: FAST_MODE_SPEED,
264 });
265 }
266 PressDuration::Long => {
267 info!("MinutesSeconds -> EditOffset");
268 return Ok(Self::EditOffset);
269 }
270 }
271 }
272 // Clock tick
273 Either::Second(tick_event) => {
274 let (_, minutes, seconds) = h12_m_s(&tick_event.local_time);
275 show_minutes_seconds(led8x12, minutes, seconds).await?;
276 }
277 }
278 }
279 }
280
281 async fn execute_edit_offset(
282 self,
283 clock_sync: &ClockSync,
284 button_watch13: &ButtonWatch13,
285 timezone_field: &TimezoneField,
286 led8x12: &Led8x12,
287 ) -> Result<Self> {
288 info!("Entering edit offset mode");
289 clock_sync.set_speed(1.0).await;
290
291 // Blink current hours and minutes with edit color accent.
292 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 loop {
301 info!("Waiting for button press in edit mode");
302 match button_watch13.wait_for_press_duration().await {
303 PressDuration::Short => {
304 info!("Short press detected - incrementing offset");
305 // Increment the offset by 1 hour
306 offset_minutes += 60;
307 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308 if offset_minutes >= ONE_DAY_MINUTES {
309 offset_minutes -= ONE_DAY_MINUTES;
310 }
311 clock_sync.set_offset_minutes(offset_minutes).await;
312 info!("New offset: {} minutes", offset_minutes);
313
314 // Update display
315 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316 info!(
317 "Updated time after offset change: {:02}:{:02}",
318 hours, minutes
319 );
320 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321 }
322 PressDuration::Long => {
323 info!("Long press detected - saving and exiting edit mode");
324 // Save to flash and exit edit mode
325 timezone_field.set_offset_minutes(offset_minutes)?;
326 info!("Offset saved to flash: {} minutes", offset_minutes);
327 return Ok(Self::HoursMinutes { speed: 1.0 });
328 }
329 }
330 }
331 }190 async fn execute_hours_minutes(
191 self,
192 speed: f32,
193 clock_sync: &ClockSync,
194 button_watch13: &ButtonWatch13,
195 led12x4: &Led12x4,
196 ) -> Result<Self> {
197 clock_sync.set_speed(speed).await;
198 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
199 show_hours_minutes(led12x4, hours, minutes).await?;
200 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
201 loop {
202 match select(
203 button_watch13.wait_for_press_duration(),
204 clock_sync.wait_for_tick(),
205 )
206 .await
207 {
208 // Button pushes
209 Either::First(press_duration) => {
210 info!(
211 "HoursMinutes: Button press detected: {:?}, speed_bits={}",
212 press_duration,
213 speed.to_bits()
214 );
215 match (press_duration, speed.to_bits()) {
216 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
217 info!("HoursMinutes -> MinutesSeconds");
218 return Ok(Self::MinutesSeconds);
219 }
220 (PressDuration::Short, _) => {
221 info!("HoursMinutes: Resetting speed to 1.0");
222 return Ok(Self::HoursMinutes { speed: 1.0 });
223 }
224 (PressDuration::Long, _) => {
225 info!("HoursMinutes -> EditOffset");
226 return Ok(Self::EditOffset);
227 }
228 }
229 }
230 // Clock tick
231 Either::Second(tick) => {
232 let (hours, minutes, _) = h12_m_s(&tick.local_time);
233 show_hours_minutes(led12x4, hours, minutes).await?;
234 }
235 }
236 }
237 }
238
239 async fn execute_minutes_seconds(
240 self,
241 clock_sync: &ClockSync,
242 button_watch13: &ButtonWatch13,
243 led12x4: &Led12x4,
244 ) -> Result<Self> {
245 clock_sync.set_speed(1.0).await;
246 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
247 show_minutes_seconds(led12x4, minutes, seconds).await?;
248 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
249 loop {
250 match select(
251 button_watch13.wait_for_press_duration(),
252 clock_sync.wait_for_tick(),
253 )
254 .await
255 {
256 // Button pushes
257 Either::First(press_duration) => {
258 info!(
259 "MinutesSeconds: Button press detected: {:?}",
260 press_duration
261 );
262 match press_duration {
263 PressDuration::Short => {
264 info!("MinutesSeconds -> HoursMinutes (fast)");
265 return Ok(Self::HoursMinutes {
266 speed: FAST_MODE_SPEED,
267 });
268 }
269 PressDuration::Long => {
270 info!("MinutesSeconds -> EditOffset");
271 return Ok(Self::EditOffset);
272 }
273 }
274 }
275 // Clock tick
276 Either::Second(tick) => {
277 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
278 show_minutes_seconds(led12x4, minutes, seconds).await?;
279 }
280 }
281 }
282 }
283
284 async fn execute_edit_offset(
285 self,
286 clock_sync: &ClockSync,
287 button_watch13: &ButtonWatch13,
288 timezone_field: &TimezoneField,
289 led12x4: &Led12x4,
290 ) -> Result<Self> {
291 info!("Entering edit offset mode");
292 clock_sync.set_speed(1.0).await;
293
294 // Blink current hours and minutes with edit color accent.
295 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298 // Get the current offset minutes from clock (source of truth)
299 let mut offset_minutes = clock_sync.offset_minutes();
300 info!("Current offset: {} minutes", offset_minutes);
301
302 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303 loop {
304 info!("Waiting for button press in edit mode");
305 match button_watch13.wait_for_press_duration().await {
306 PressDuration::Short => {
307 info!("Short press detected - incrementing offset");
308 // Increment the offset by 1 hour
309 offset_minutes += 60;
310 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311 if offset_minutes >= ONE_DAY_MINUTES {
312 offset_minutes -= ONE_DAY_MINUTES;
313 }
314 clock_sync.set_offset_minutes(offset_minutes).await;
315 info!("New offset: {} minutes", offset_minutes);
316
317 // Update display (atomic already updated, can use now_local)
318 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319 info!(
320 "Updated time after offset change: {:02}:{:02}",
321 hours, minutes
322 );
323 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324 }
325 PressDuration::Long => {
326 info!("Long press detected - saving and exiting edit mode");
327 // Save to flash and exit edit mode
328 timezone_field.set_offset_minutes(offset_minutes)?;
329 info!("Offset saved to flash: {} minutes", offset_minutes);
330 return Ok(Self::HoursMinutes { speed: 1.0 });
331 }
332 }
333 }
334 }168 async fn execute_hours_minutes(
169 self,
170 speed: f32,
171 clock_sync: &ClockSync,
172 button_watch13: &ButtonWatch13,
173 led4: &Led4<'_>,
174 ) -> Result<Self> {
175 clock_sync.set_speed(speed).await;
176 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
177 led4.write_text(
178 [
179 Self::tens_hours(hours),
180 Self::ones_digit(hours),
181 Self::tens_digit(minutes),
182 Self::ones_digit(minutes),
183 ],
184 BlinkState::Solid,
185 );
186 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
187 loop {
188 match select(
189 button_watch13.wait_for_press_duration(),
190 clock_sync.wait_for_tick(),
191 )
192 .await
193 {
194 // Button pushes
195 Either::First(press_duration) => match (press_duration, speed.to_bits()) {
196 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
197 return Ok(Self::MinutesSeconds);
198 }
199 (PressDuration::Short, _) => {
200 return Ok(Self::HoursMinutes { speed: 1.0 });
201 }
202 (PressDuration::Long, _) => {
203 return Ok(Self::EditOffset);
204 }
205 },
206 // Clock tick
207 Either::Second(tick) => {
208 let (hours, minutes, _) = h12_m_s(&tick.local_time);
209 led4.write_text(
210 [
211 Self::tens_hours(hours),
212 Self::ones_digit(hours),
213 Self::tens_digit(minutes),
214 Self::ones_digit(minutes),
215 ],
216 BlinkState::Solid,
217 );
218 }
219 }
220 }
221 }
222
223 async fn execute_minutes_seconds(
224 self,
225 clock_sync: &ClockSync,
226 button_watch13: &ButtonWatch13,
227 led4: &Led4<'_>,
228 ) -> Result<Self> {
229 clock_sync.set_speed(1.0).await;
230 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
231 led4.write_text(
232 [
233 Self::tens_digit(minutes),
234 Self::ones_digit(minutes),
235 Self::tens_digit(seconds),
236 Self::ones_digit(seconds),
237 ],
238 BlinkState::Solid,
239 );
240 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
241 loop {
242 match select(
243 button_watch13.wait_for_press_duration(),
244 clock_sync.wait_for_tick(),
245 )
246 .await
247 {
248 // Button pushes
249 Either::First(PressDuration::Short) => {
250 return Ok(Self::HoursMinutes {
251 speed: FAST_MODE_SPEED,
252 });
253 }
254 Either::First(PressDuration::Long) => {
255 return Ok(Self::EditOffset);
256 }
257 // Clock tick
258 Either::Second(tick) => {
259 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
260 led4.write_text(
261 [
262 Self::tens_digit(minutes),
263 Self::ones_digit(minutes),
264 Self::tens_digit(seconds),
265 Self::ones_digit(seconds),
266 ],
267 BlinkState::Solid,
268 );
269 }
270 }
271 }
272 }
273
274 async fn execute_edit_offset(
275 self,
276 clock_sync: &ClockSync,
277 button_watch13: &ButtonWatch13,
278 timezone_field: &TimezoneField,
279 led4: &Led4<'_>,
280 ) -> Result<Self> {
281 info!("Entering edit offset mode");
282
283 // Blink current hours and minutes
284 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285 led4.write_text(
286 [
287 Self::tens_hours(hours),
288 Self::ones_digit(hours),
289 Self::tens_digit(minutes),
290 Self::ones_digit(minutes),
291 ],
292 BlinkState::BlinkingAndOn,
293 );
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 clock_sync.set_speed(1.0).await;
301 loop {
302 info!("Waiting for button press in edit mode");
303 match button_watch13.wait_for_press_duration().await {
304 PressDuration::Short => {
305 info!("Short press detected - incrementing offset");
306 // Increment the offset by 1 hour
307 offset_minutes += 60;
308 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309 if offset_minutes >= ONE_DAY_MINUTES {
310 offset_minutes -= ONE_DAY_MINUTES;
311 }
312 clock_sync.set_offset_minutes(offset_minutes).await;
313 info!("New offset: {} minutes", offset_minutes);
314
315 // Update display (atomic already updated, can use now_local)
316 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317 info!(
318 "Updated time after offset change: {:02}:{:02}",
319 hours, minutes
320 );
321 led4.write_text(
322 [
323 Self::tens_hours(hours),
324 Self::ones_digit(hours),
325 Self::tens_digit(minutes),
326 Self::ones_digit(minutes),
327 ],
328 BlinkState::BlinkingAndOn,
329 );
330 }
331 PressDuration::Long => {
332 info!("Long press detected - saving and exiting edit mode");
333 // Save to flash and exit edit mode
334 timezone_field.set_offset_minutes(offset_minutes)?;
335 info!("Offset saved to flash: {} minutes", offset_minutes);
336 return Ok(Self::HoursMinutes { speed: 1.0 });
337 }
338 }
339 }
340 }Sourcepub async fn set_speed(&self, speed_multiplier: f32)
pub async fn set_speed(&self, speed_multiplier: f32)
Update the speed multiplier (1.0 = real time).
Examples found in repository?
171 async fn execute_hours_minutes(
172 self,
173 speed: f32,
174 clock_sync: &ClockSync,
175 button_watch13: &ButtonWatch13,
176 servo_display: &ServoClockDisplay,
177 ) -> Result<Self> {
178 clock_sync.set_speed(speed).await;
179 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
180 servo_display.show_hours_minutes(hours, minutes).await;
181 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
182 loop {
183 match select(
184 button_watch13.wait_for_press_duration(),
185 clock_sync.wait_for_tick(),
186 )
187 .await
188 {
189 // Button pushes
190 Either::First(press_duration) => match (press_duration, speed.to_bits()) {
191 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
192 return Ok(Self::MinutesSeconds);
193 }
194 (PressDuration::Short, _) => {
195 return Ok(Self::HoursMinutes { speed: 1.0 });
196 }
197 (PressDuration::Long, _) => {
198 return Ok(Self::EditOffset);
199 }
200 },
201 // Clock tick
202 Either::Second(tick) => {
203 let (hours, minutes, _) = h12_m_s(&tick.local_time);
204 servo_display.show_hours_minutes(hours, minutes).await;
205 }
206 }
207 }
208 }
209
210 async fn execute_minutes_seconds(
211 self,
212 clock_sync: &ClockSync,
213 button_watch13: &ButtonWatch13,
214 servo_display: &ServoClockDisplay,
215 ) -> Result<Self> {
216 clock_sync.set_speed(1.0).await;
217 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
218 servo_display.show_minutes_seconds(minutes, seconds).await;
219 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
220 loop {
221 match select(
222 button_watch13.wait_for_press_duration(),
223 clock_sync.wait_for_tick(),
224 )
225 .await
226 {
227 // Button pushes
228 Either::First(PressDuration::Short) => {
229 return Ok(Self::HoursMinutes {
230 speed: FAST_MODE_SPEED,
231 });
232 }
233 Either::First(PressDuration::Long) => {
234 return Ok(Self::EditOffset);
235 }
236 // Clock tick
237 Either::Second(tick) => {
238 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
239 servo_display.show_minutes_seconds(minutes, seconds).await;
240 }
241 }
242 }
243 }
244
245 async fn execute_edit_offset(
246 self,
247 clock_sync: &ClockSync,
248 button_watch13: &ButtonWatch13,
249 timezone_field: &TimezoneField,
250 servo_display: &ServoClockDisplay,
251 ) -> Result<Self> {
252 info!("Entering edit offset mode");
253 clock_sync.set_speed(1.0).await;
254
255 // Show current hours and minutes
256 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257 servo_display
258 .show_hours_minutes_indicator(hours, minutes)
259 .await;
260 // Add a gentle wiggle on the bottom servo to signal edit mode.
261 const WIGGLE: [(u16, Duration); 2] = [
262 (80, Duration::from_millis(250)),
263 (100, Duration::from_millis(250)),
264 ];
265 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267 // Get the current offset minutes from clock (source of truth)
268 let mut offset_minutes = clock_sync.offset_minutes();
269 info!("Current offset: {} minutes", offset_minutes);
270
271 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272 loop {
273 info!("Waiting for button press in edit mode");
274 match button_watch13.wait_for_press_duration().await {
275 PressDuration::Short => {
276 info!("Short press detected - incrementing offset");
277 // Increment the offset by 1 hour
278 offset_minutes += 60;
279 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280 if offset_minutes >= ONE_DAY_MINUTES {
281 offset_minutes -= ONE_DAY_MINUTES;
282 }
283 clock_sync.set_offset_minutes(offset_minutes).await;
284 info!("New offset: {} minutes", offset_minutes);
285
286 // Update display (atomic already updated, can use now_local)
287 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288 info!(
289 "Updated time after offset change: {:02}:{:02}",
290 hours, minutes
291 );
292 servo_display
293 .show_hours_minutes_indicator(hours, minutes)
294 .await;
295 servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296 }
297 PressDuration::Long => {
298 info!("Long press detected - saving and exiting edit mode");
299 // Save to flash and exit edit mode
300 timezone_field.set_offset_minutes(offset_minutes)?;
301 info!("Offset saved to flash: {} minutes", offset_minutes);
302 return Ok(Self::HoursMinutes { speed: 1.0 });
303 }
304 }
305 }
306 }More examples
197 async fn execute_hours_minutes(
198 self,
199 speed: f32,
200 clock_sync: &ClockSync,
201 button_watch13: &ButtonWatch13,
202 led8x12: &Led8x12,
203 ) -> Result<Self> {
204 clock_sync.set_speed(speed).await;
205 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
206 show_hours_minutes(led8x12, hours, minutes).await?;
207 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
208 loop {
209 match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
210 // Button pushes
211 Either::First(press_duration) => {
212 info!(
213 "HoursMinutes: Button press detected: {:?}, speed_bits={}",
214 press_duration,
215 speed.to_bits()
216 );
217 match (press_duration, speed.to_bits()) {
218 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
219 info!("HoursMinutes -> MinutesSeconds");
220 return Ok(Self::MinutesSeconds);
221 }
222 (PressDuration::Short, _) => {
223 info!("HoursMinutes: Resetting speed to 1.0");
224 return Ok(Self::HoursMinutes { speed: 1.0 });
225 }
226 (PressDuration::Long, _) => {
227 info!("HoursMinutes -> EditOffset");
228 return Ok(Self::EditOffset);
229 }
230 }
231 }
232 // Clock tick
233 Either::Second(tick_event) => {
234 let (hours, minutes, _) = h12_m_s(&tick_event.local_time);
235 show_hours_minutes(led8x12, hours, minutes).await?;
236 }
237 }
238 }
239 }
240
241 async fn execute_minutes_seconds(
242 self,
243 clock_sync: &ClockSync,
244 button_watch13: &ButtonWatch13,
245 led8x12: &Led8x12,
246 ) -> Result<Self> {
247 clock_sync.set_speed(1.0).await;
248 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
249 show_minutes_seconds(led8x12, minutes, seconds).await?;
250 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
251 loop {
252 match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
253 // Button pushes
254 Either::First(press_duration) => {
255 info!(
256 "MinutesSeconds: Button press detected: {:?}",
257 press_duration
258 );
259 match press_duration {
260 PressDuration::Short => {
261 info!("MinutesSeconds -> HoursMinutes (fast)");
262 return Ok(Self::HoursMinutes {
263 speed: FAST_MODE_SPEED,
264 });
265 }
266 PressDuration::Long => {
267 info!("MinutesSeconds -> EditOffset");
268 return Ok(Self::EditOffset);
269 }
270 }
271 }
272 // Clock tick
273 Either::Second(tick_event) => {
274 let (_, minutes, seconds) = h12_m_s(&tick_event.local_time);
275 show_minutes_seconds(led8x12, minutes, seconds).await?;
276 }
277 }
278 }
279 }
280
281 async fn execute_edit_offset(
282 self,
283 clock_sync: &ClockSync,
284 button_watch13: &ButtonWatch13,
285 timezone_field: &TimezoneField,
286 led8x12: &Led8x12,
287 ) -> Result<Self> {
288 info!("Entering edit offset mode");
289 clock_sync.set_speed(1.0).await;
290
291 // Blink current hours and minutes with edit color accent.
292 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 loop {
301 info!("Waiting for button press in edit mode");
302 match button_watch13.wait_for_press_duration().await {
303 PressDuration::Short => {
304 info!("Short press detected - incrementing offset");
305 // Increment the offset by 1 hour
306 offset_minutes += 60;
307 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308 if offset_minutes >= ONE_DAY_MINUTES {
309 offset_minutes -= ONE_DAY_MINUTES;
310 }
311 clock_sync.set_offset_minutes(offset_minutes).await;
312 info!("New offset: {} minutes", offset_minutes);
313
314 // Update display
315 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316 info!(
317 "Updated time after offset change: {:02}:{:02}",
318 hours, minutes
319 );
320 show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321 }
322 PressDuration::Long => {
323 info!("Long press detected - saving and exiting edit mode");
324 // Save to flash and exit edit mode
325 timezone_field.set_offset_minutes(offset_minutes)?;
326 info!("Offset saved to flash: {} minutes", offset_minutes);
327 return Ok(Self::HoursMinutes { speed: 1.0 });
328 }
329 }
330 }
331 }190 async fn execute_hours_minutes(
191 self,
192 speed: f32,
193 clock_sync: &ClockSync,
194 button_watch13: &ButtonWatch13,
195 led12x4: &Led12x4,
196 ) -> Result<Self> {
197 clock_sync.set_speed(speed).await;
198 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
199 show_hours_minutes(led12x4, hours, minutes).await?;
200 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
201 loop {
202 match select(
203 button_watch13.wait_for_press_duration(),
204 clock_sync.wait_for_tick(),
205 )
206 .await
207 {
208 // Button pushes
209 Either::First(press_duration) => {
210 info!(
211 "HoursMinutes: Button press detected: {:?}, speed_bits={}",
212 press_duration,
213 speed.to_bits()
214 );
215 match (press_duration, speed.to_bits()) {
216 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
217 info!("HoursMinutes -> MinutesSeconds");
218 return Ok(Self::MinutesSeconds);
219 }
220 (PressDuration::Short, _) => {
221 info!("HoursMinutes: Resetting speed to 1.0");
222 return Ok(Self::HoursMinutes { speed: 1.0 });
223 }
224 (PressDuration::Long, _) => {
225 info!("HoursMinutes -> EditOffset");
226 return Ok(Self::EditOffset);
227 }
228 }
229 }
230 // Clock tick
231 Either::Second(tick) => {
232 let (hours, minutes, _) = h12_m_s(&tick.local_time);
233 show_hours_minutes(led12x4, hours, minutes).await?;
234 }
235 }
236 }
237 }
238
239 async fn execute_minutes_seconds(
240 self,
241 clock_sync: &ClockSync,
242 button_watch13: &ButtonWatch13,
243 led12x4: &Led12x4,
244 ) -> Result<Self> {
245 clock_sync.set_speed(1.0).await;
246 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
247 show_minutes_seconds(led12x4, minutes, seconds).await?;
248 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
249 loop {
250 match select(
251 button_watch13.wait_for_press_duration(),
252 clock_sync.wait_for_tick(),
253 )
254 .await
255 {
256 // Button pushes
257 Either::First(press_duration) => {
258 info!(
259 "MinutesSeconds: Button press detected: {:?}",
260 press_duration
261 );
262 match press_duration {
263 PressDuration::Short => {
264 info!("MinutesSeconds -> HoursMinutes (fast)");
265 return Ok(Self::HoursMinutes {
266 speed: FAST_MODE_SPEED,
267 });
268 }
269 PressDuration::Long => {
270 info!("MinutesSeconds -> EditOffset");
271 return Ok(Self::EditOffset);
272 }
273 }
274 }
275 // Clock tick
276 Either::Second(tick) => {
277 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
278 show_minutes_seconds(led12x4, minutes, seconds).await?;
279 }
280 }
281 }
282 }
283
284 async fn execute_edit_offset(
285 self,
286 clock_sync: &ClockSync,
287 button_watch13: &ButtonWatch13,
288 timezone_field: &TimezoneField,
289 led12x4: &Led12x4,
290 ) -> Result<Self> {
291 info!("Entering edit offset mode");
292 clock_sync.set_speed(1.0).await;
293
294 // Blink current hours and minutes with edit color accent.
295 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298 // Get the current offset minutes from clock (source of truth)
299 let mut offset_minutes = clock_sync.offset_minutes();
300 info!("Current offset: {} minutes", offset_minutes);
301
302 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303 loop {
304 info!("Waiting for button press in edit mode");
305 match button_watch13.wait_for_press_duration().await {
306 PressDuration::Short => {
307 info!("Short press detected - incrementing offset");
308 // Increment the offset by 1 hour
309 offset_minutes += 60;
310 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311 if offset_minutes >= ONE_DAY_MINUTES {
312 offset_minutes -= ONE_DAY_MINUTES;
313 }
314 clock_sync.set_offset_minutes(offset_minutes).await;
315 info!("New offset: {} minutes", offset_minutes);
316
317 // Update display (atomic already updated, can use now_local)
318 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319 info!(
320 "Updated time after offset change: {:02}:{:02}",
321 hours, minutes
322 );
323 show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324 }
325 PressDuration::Long => {
326 info!("Long press detected - saving and exiting edit mode");
327 // Save to flash and exit edit mode
328 timezone_field.set_offset_minutes(offset_minutes)?;
329 info!("Offset saved to flash: {} minutes", offset_minutes);
330 return Ok(Self::HoursMinutes { speed: 1.0 });
331 }
332 }
333 }
334 }168 async fn execute_hours_minutes(
169 self,
170 speed: f32,
171 clock_sync: &ClockSync,
172 button_watch13: &ButtonWatch13,
173 led4: &Led4<'_>,
174 ) -> Result<Self> {
175 clock_sync.set_speed(speed).await;
176 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
177 led4.write_text(
178 [
179 Self::tens_hours(hours),
180 Self::ones_digit(hours),
181 Self::tens_digit(minutes),
182 Self::ones_digit(minutes),
183 ],
184 BlinkState::Solid,
185 );
186 clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
187 loop {
188 match select(
189 button_watch13.wait_for_press_duration(),
190 clock_sync.wait_for_tick(),
191 )
192 .await
193 {
194 // Button pushes
195 Either::First(press_duration) => match (press_duration, speed.to_bits()) {
196 (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
197 return Ok(Self::MinutesSeconds);
198 }
199 (PressDuration::Short, _) => {
200 return Ok(Self::HoursMinutes { speed: 1.0 });
201 }
202 (PressDuration::Long, _) => {
203 return Ok(Self::EditOffset);
204 }
205 },
206 // Clock tick
207 Either::Second(tick) => {
208 let (hours, minutes, _) = h12_m_s(&tick.local_time);
209 led4.write_text(
210 [
211 Self::tens_hours(hours),
212 Self::ones_digit(hours),
213 Self::tens_digit(minutes),
214 Self::ones_digit(minutes),
215 ],
216 BlinkState::Solid,
217 );
218 }
219 }
220 }
221 }
222
223 async fn execute_minutes_seconds(
224 self,
225 clock_sync: &ClockSync,
226 button_watch13: &ButtonWatch13,
227 led4: &Led4<'_>,
228 ) -> Result<Self> {
229 clock_sync.set_speed(1.0).await;
230 let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
231 led4.write_text(
232 [
233 Self::tens_digit(minutes),
234 Self::ones_digit(minutes),
235 Self::tens_digit(seconds),
236 Self::ones_digit(seconds),
237 ],
238 BlinkState::Solid,
239 );
240 clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
241 loop {
242 match select(
243 button_watch13.wait_for_press_duration(),
244 clock_sync.wait_for_tick(),
245 )
246 .await
247 {
248 // Button pushes
249 Either::First(PressDuration::Short) => {
250 return Ok(Self::HoursMinutes {
251 speed: FAST_MODE_SPEED,
252 });
253 }
254 Either::First(PressDuration::Long) => {
255 return Ok(Self::EditOffset);
256 }
257 // Clock tick
258 Either::Second(tick) => {
259 let (_, minutes, seconds) = h12_m_s(&tick.local_time);
260 led4.write_text(
261 [
262 Self::tens_digit(minutes),
263 Self::ones_digit(minutes),
264 Self::tens_digit(seconds),
265 Self::ones_digit(seconds),
266 ],
267 BlinkState::Solid,
268 );
269 }
270 }
271 }
272 }
273
274 async fn execute_edit_offset(
275 self,
276 clock_sync: &ClockSync,
277 button_watch13: &ButtonWatch13,
278 timezone_field: &TimezoneField,
279 led4: &Led4<'_>,
280 ) -> Result<Self> {
281 info!("Entering edit offset mode");
282
283 // Blink current hours and minutes
284 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285 led4.write_text(
286 [
287 Self::tens_hours(hours),
288 Self::ones_digit(hours),
289 Self::tens_digit(minutes),
290 Self::ones_digit(minutes),
291 ],
292 BlinkState::BlinkingAndOn,
293 );
294
295 // Get the current offset minutes from clock (source of truth)
296 let mut offset_minutes = clock_sync.offset_minutes();
297 info!("Current offset: {} minutes", offset_minutes);
298
299 clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300 clock_sync.set_speed(1.0).await;
301 loop {
302 info!("Waiting for button press in edit mode");
303 match button_watch13.wait_for_press_duration().await {
304 PressDuration::Short => {
305 info!("Short press detected - incrementing offset");
306 // Increment the offset by 1 hour
307 offset_minutes += 60;
308 const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309 if offset_minutes >= ONE_DAY_MINUTES {
310 offset_minutes -= ONE_DAY_MINUTES;
311 }
312 clock_sync.set_offset_minutes(offset_minutes).await;
313 info!("New offset: {} minutes", offset_minutes);
314
315 // Update display (atomic already updated, can use now_local)
316 let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317 info!(
318 "Updated time after offset change: {:02}:{:02}",
319 hours, minutes
320 );
321 led4.write_text(
322 [
323 Self::tens_hours(hours),
324 Self::ones_digit(hours),
325 Self::tens_digit(minutes),
326 Self::ones_digit(minutes),
327 ],
328 BlinkState::BlinkingAndOn,
329 );
330 }
331 PressDuration::Long => {
332 info!("Long press detected - saving and exiting edit mode");
333 // Save to flash and exit edit mode
334 timezone_field.set_offset_minutes(offset_minutes)?;
335 info!("Offset saved to flash: {} minutes", offset_minutes);
336 return Ok(Self::HoursMinutes { speed: 1.0 });
337 }
338 }
339 }
340 }Sourcepub async fn set_utc_time(&self, unix_seconds: UnixSeconds)
pub async fn set_utc_time(&self, unix_seconds: UnixSeconds)
Manually set the current UTC time and mark the clock as synced.
Auto Trait Implementations§
impl Freeze for ClockSync
impl !RefUnwindSafe for ClockSync
impl Send for ClockSync
impl Sync for ClockSync
impl Unpin for ClockSync
impl !UnwindSafe for ClockSync
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CheckedAs for T
impl<T> CheckedAs for T
Source§fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
Source§impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
Source§fn checked_cast_from(src: Src) -> Option<Dst>
fn checked_cast_from(src: Src) -> Option<Dst>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more