Skip to content

Commit 34250ea

Browse files
committed
rework durations
1 parent 9844981 commit 34250ea

File tree

5 files changed

+129
-176
lines changed

5 files changed

+129
-176
lines changed

src/bin/control_panel.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use embassy_executor::Spawner;
1212
use embassy_time::{Duration, Timer};
1313
use esp_backtrace as _;
1414
use esp_hal::clock::CpuClock;
15-
use esp_hal::gpio::{Input, InputConfig, Pull};
15+
use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull};
1616
use esp_hal::timer::systimer::SystemTimer;
1717
use esp_hal::{
1818
uart::{Config, RxConfig, Uart},
@@ -43,18 +43,32 @@ async fn main(spawner: Spawner) {
4343

4444
info!("Embassy initialized!");
4545

46-
let tx_pin = peripherals.GPIO21;
46+
let usb_switch_led_a = Input::new(
47+
peripherals.GPIO20,
48+
InputConfig::default().with_pull(Pull::Down),
49+
);
50+
let usb_switch_led_b = Input::new(
51+
peripherals.GPIO21,
52+
InputConfig::default().with_pull(Pull::Down),
53+
);
4754

48-
let config = Config::default().with_rx(
55+
let usb_power_2 = Output::new(peripherals.GPIO9, Level::Low, OutputConfig::default());
56+
57+
let meeting_sign_power = Output::new(peripherals.GPIO6, Level::Low, OutputConfig::default());
58+
// This signal should be 3.3V high when the Meeting Sign is operating correctly
59+
let meeting_sign_sense = Input::new(
60+
peripherals.GPIO7,
61+
InputConfig::default().with_pull(Pull::Down),
62+
);
63+
let meeting_sign_uart_pin = peripherals.GPIO8;
64+
let meeting_sign_uart_config = Config::default().with_rx(
4965
RxConfig::default().with_fifo_full_threshold(meeting_instruction::READ_BUF_SIZE as u16),
5066
);
51-
52-
let uart = Uart::new(peripherals.UART0, config)
67+
let meeting_sign_uart = Uart::new(peripherals.UART0, meeting_sign_uart_config)
5368
.unwrap()
54-
.with_tx(tx_pin)
69+
.with_tx(meeting_sign_uart_pin)
5570
.into_async();
56-
57-
spawner.spawn(writer(uart)).ok();
71+
spawner.spawn(writer(meeting_sign_uart)).ok();
5872

5973
let rotary_encoder_button = Input::new(peripherals.GPIO0, InputConfig::default());
6074
info!(
@@ -133,7 +147,13 @@ async fn writer(mut uart: Uart<'static, Async>) {
133147
for num_minutes in 1..=120 {
134148
let duration =
135149
MeetingDuration::from_minutes(num_minutes).expect("Could not create duration");
136-
let payload: MeetingSignInstruction = duration.into();
150+
let payload = MeetingSignInstruction::On(
151+
meeting_instruction::ProgressRatio::from_durations(
152+
&duration.into(),
153+
&MeetingDuration::MAX.into(),
154+
)
155+
.expect("Invalid progress ratio"),
156+
);
137157

138158
// Serialize the payload
139159
let serialized = postcard::to_slice(&payload, &mut serialize_buf).unwrap();

src/bin/meeting_sign.rs

Lines changed: 49 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
)]
88

99
use desk_control_panel::meeting_instruction::{
10-
self, MeetingSignInstruction, UART_COMMUNICATION_TIMEOUT,
10+
self, MeetingSignInstruction, ProgressRatio, UART_COMMUNICATION_TIMEOUT,
1111
};
1212
use embassy_executor::Spawner;
1313
use embassy_futures::select::{select, Either};
@@ -23,7 +23,6 @@ use esp_hal::{
2323
Async,
2424
};
2525
use log::{debug, error, info, trace, warn, LevelFilter};
26-
use micromath::F32Ext;
2726
use static_cell::StaticCell;
2827

2928
const NUM_LEDS: usize = 9;
@@ -42,15 +41,15 @@ static mut PANIC_PIN: Option<Output<'static>> = None;
4241
#[derive(Clone)]
4342
enum MeetingSignState {
4443
NoUart,
45-
Uart,
44+
Uart(MeetingSignInstruction),
4645
}
4746

4847
type LEDsMutex = Mutex<CriticalSectionRawMutex, LEDs<'static>>;
4948
static LEDS: StaticCell<LEDsMutex> = StaticCell::new();
5049

5150
const STATE_PUB_SUB_CAPACITY: usize = 1;
5251
const STATE_NUM_PUBLISHERS: usize = 0;
53-
const STATE_NUM_SUBSCRIBERS: usize = 3;
52+
const STATE_NUM_SUBSCRIBERS: usize = 2;
5453
type MeetingSignStatePubSubChannel = PubSubChannel<
5554
CriticalSectionRawMutex,
5655
MeetingSignState,
@@ -122,12 +121,9 @@ async fn main(spawner: Spawner) {
122121
let state_subscriber_1 = meeting_sign_state
123122
.subscriber()
124123
.expect("Failed to create state subscriber 1");
125-
let state_subscriber_2 = meeting_sign_state
124+
let mut state_subscriber_2 = meeting_sign_state
126125
.subscriber()
127126
.expect("Failed to create state subscriber 2");
128-
let mut state_subscriber_3 = meeting_sign_state
129-
.subscriber()
130-
.expect("Failed to create state subscriber 3");
131127

132128
let rx_pin = peripherals.GPIO1;
133129
let uart_config = Config::default().with_rx(
@@ -138,63 +134,46 @@ async fn main(spawner: Spawner) {
138134
.with_rx(rx_pin)
139135
.into_async();
140136

137+
spawner.spawn(uart_reader(uart, state_publisher_1)).ok();
141138
spawner
142-
.spawn(uart_reader(uart, state_publisher_1, state_subscriber_1))
143-
.ok();
144-
spawner
145-
.spawn(uart_timeout_monitor(state_publisher_2, state_subscriber_2))
139+
.spawn(uart_timeout_monitor(state_publisher_2, state_subscriber_1))
146140
.ok();
147141

148-
// Initialize hardcoded timer if no UART within threshold
149-
match select(
150-
state_subscriber_3.next_message_pure(),
151-
Timer::after(UART_COMMUNICATION_TIMEOUT),
152-
)
153-
.await
154-
{
155-
Either::First(state) => {
156-
match state {
157-
MeetingSignState::NoUart => {
158-
info!("State changed to NoUart.");
159-
// Turn off all LEDs
160-
leds.lock().await.set_portion_high(1.0, 2.0);
161-
}
162-
MeetingSignState::Uart => {
163-
info!("State changed to Uart.");
164-
// Set LEDs to indicate UART communication
165-
leds.lock().await.set_portion_high(1.0, 1.0);
166-
}
167-
}
168-
}
169-
Either::Second(_) => {
170-
info!("No initial state change detected within {}s, initializing LEDs according to hardcoded timer...",
171-
UART_COMMUNICATION_TIMEOUT.as_secs());
172-
}
173-
}
174-
142+
// Main loop
175143
loop {
176144
match select(
177-
state_subscriber_3.next_message_pure(),
178-
Timer::after_secs(60),
145+
state_subscriber_2.next_message_pure(),
146+
Timer::after(UART_COMMUNICATION_TIMEOUT),
179147
)
180148
.await
181149
{
182-
Either::First(state) => {
183-
match state {
184-
MeetingSignState::NoUart => {
185-
info!("State changed to NoUart.");
186-
// Turn off all LEDs
187-
leds.lock().await.set_portion_high(1.0, 2.0);
188-
}
189-
MeetingSignState::Uart => {
190-
info!("State changed to Uart.");
191-
// Set LEDs to indicate UART communication
192-
leds.lock().await.set_portion_high(1.0, 1.0);
150+
Either::First(state) => match state {
151+
MeetingSignState::NoUart => {
152+
info!("Initial state changed to NoUart.");
153+
leds.lock().await.set_ratio_low(ProgressRatio(u8::MAX / 2));
154+
}
155+
MeetingSignState::Uart(instruction) => {
156+
info!("Initial state changed to Uart.");
157+
match instruction {
158+
MeetingSignInstruction::On(progress_ratio) => {
159+
leds.lock().await.set_ratio_low(progress_ratio)
160+
}
161+
MeetingSignInstruction::Off => {
162+
leds.lock().await.set_ratio_low(ProgressRatio(0))
163+
}
164+
MeetingSignInstruction::Diagnostic => todo!(),
193165
}
166+
leds.lock().await.set_ratio_low(ProgressRatio(u8::MAX));
194167
}
195-
}
168+
},
196169
Either::Second(_) => {
197-
info!("No state change detected within 60 seconds, updating LEDs according to internal timer...");
170+
info!("No initial state change detected within {}s, initializing LEDs according to builtin timer...",
171+
UART_COMMUNICATION_TIMEOUT.as_secs());
172+
173+
// leds.lock().await.display_builtin_timer();
174+
leds.lock().await.set_pattern_array(&[
175+
false, true, true, false, false, false, true, true, false,
176+
]);
198177
}
199178
}
200179
}
@@ -211,38 +190,30 @@ impl<'a> LEDs<'a> {
211190
Self { led_outs }
212191
}
213192

214-
/// Set the portion of LEDs to high based on the given numerator and denominator.
215-
pub fn set_portion_high(&mut self, numerator: f32, denominator: f32) {
216-
let num_on_leds = if numerator <= 0.0 || denominator <= 0.0 {
217-
warn!(
218-
"Invalid portion values: numerator {}, denominator {}",
219-
numerator, denominator
220-
);
221-
0 // This will turn off all LEDs
222-
} else {
223-
(NUM_LEDS as f32 * numerator / denominator).round() as usize
224-
};
193+
/// Set the portion of LEDs to low based on the given numerator and denominator.
194+
pub fn set_ratio_low(&mut self, ratio: ProgressRatio) {
195+
let num_on_leds = ratio.apply_to(NUM_LEDS);
225196

226197
for (led_idx, led) in self.led_outs.iter_mut().enumerate() {
227198
if led_idx < num_on_leds {
228-
led.set_high();
229-
} else {
230199
led.set_low();
200+
} else {
201+
led.set_high();
231202
}
232203
}
233204
}
234205

235-
pub fn set_pattern(&mut self, pattern: u16) {
236-
for (i, led) in self.led_outs.iter_mut().enumerate() {
237-
if pattern & (1 << i) != 0 {
206+
pub fn set_pattern_array(&mut self, pattern: &[bool; NUM_LEDS]) {
207+
for (led, &should_be_on) in self.led_outs.iter_mut().zip(pattern.iter()) {
208+
if should_be_on {
238209
led.set_high();
239210
} else {
240211
led.set_low();
241212
}
242213
}
243214
}
244215

245-
pub fn display_current_timer(&mut self) {
216+
pub fn display_builtin_timer(&mut self) {
246217
let on_duration = Instant::now().elapsed();
247218
if on_duration >= DEFAULT_MAX_DURATION {
248219
// If the timer has expired, turn off all LEDs
@@ -251,50 +222,18 @@ impl<'a> LEDs<'a> {
251222
}
252223
} else {
253224
// Calculate the portion of time elapsed
254-
let portion = on_duration.as_secs() as f32 / DEFAULT_MAX_DURATION.as_secs() as f32;
255-
assert!(
256-
portion >= 0.0,
257-
"Portion is zero or negative: {on_duration} / {DEFAULT_MAX_DURATION} = {}",
258-
portion
259-
);
225+
let ratio = ProgressRatio::from_durations(&on_duration, &DEFAULT_MAX_DURATION)
226+
.expect("Failed to calculate ratio from durations");
260227
// Set LEDs based on the portion
261-
self.set_portion_high(
262-
on_duration.as_secs() as f32,
263-
DEFAULT_MAX_DURATION.as_secs() as f32,
264-
);
265-
}
266-
}
267-
}
268-
269-
#[derive(Clone, Copy)]
270-
struct Progress {
271-
elapsed: u32,
272-
total: u32,
273-
}
274-
275-
impl Progress {
276-
fn new(current: u32, total: u32) -> Self {
277-
Self { current, total }
278-
}
279-
280-
fn as_ratio(&self) -> f32 {
281-
if self.total == 0 {
282-
0.0
283-
} else {
284-
self.current as f32 / self.total as f32
228+
self.set_ratio_low(ratio);
285229
}
286230
}
287231
}
288232

289-
fn set_progress(&mut self, progress: Progress) {
290-
self.set_portion_high(progress.as_ratio());
291-
}
292-
293233
#[embassy_executor::task]
294234
async fn uart_reader(
295235
mut uart: Uart<'static, Async>,
296236
state_publisher: MeetingSignStatePublisher<'static>,
297-
mut state_subscriber: MeetingSignStateSubscriber<'static>,
298237
) {
299238
debug!("Starting UART reader task");
300239

@@ -322,18 +261,8 @@ async fn uart_reader(
322261
match postcard::from_bytes::<MeetingSignInstruction>(decoded_data) {
323262
Ok(instruction) => {
324263
debug!("Received: {:?}", instruction);
325-
match state_subscriber.try_next_message_pure() {
326-
None | Some(MeetingSignState::NoUart) => {
327-
// If we were not in UART state, switch to UART
328-
debug!("Switching state to UART");
329-
state_publisher
330-
.publish_immediate(MeetingSignState::Uart);
331-
}
332-
Some(MeetingSignState::Uart) => {
333-
// Already in UART state, just log
334-
debug!("Already in UART state, processing instruction");
335-
}
336-
}
264+
state_publisher
265+
.publish_immediate(MeetingSignState::Uart(instruction));
337266
}
338267
Err(e) => warn!("Deserialization error: {:?}", e),
339268
}
@@ -367,7 +296,7 @@ async fn uart_timeout_monitor(
367296
// Wait for UART state
368297
loop {
369298
match state_subscriber.next_message_pure().await {
370-
MeetingSignState::Uart => break, // Start monitoring
299+
MeetingSignState::Uart(_) => break, // Start monitoring
371300
MeetingSignState::NoUart => continue, // Keep waiting
372301
}
373302
}
@@ -379,7 +308,7 @@ async fn uart_timeout_monitor(
379308
match select(state_subscriber.next_message_pure(), &mut timeout_timer).await {
380309
Either::First(state) => {
381310
match state {
382-
MeetingSignState::Uart => {
311+
MeetingSignState::Uart(_) => {
383312
// New UART message received, reset the timer
384313
debug!("UART activity detected, resetting timeout");
385314
timeout_timer = Timer::after(UART_COMMUNICATION_TIMEOUT);

src/meeting_duration.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ impl TryFrom<Duration> for MeetingDuration {
8282
}
8383
}
8484

85+
impl From<MeetingDuration> for Duration {
86+
fn from(meeting_duration: MeetingDuration) -> Self {
87+
meeting_duration.0
88+
}
89+
}
90+
8591
// Easy access to the inner Duration
8692
impl AsRef<Duration> for MeetingDuration {
8793
fn as_ref(&self) -> &Duration {

0 commit comments

Comments
 (0)